473,757 Members | 10,708 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

printf("%p\n", (void *)0);

printf("%p\n", (void *)0); /* UB, or not? Please explain your answer. */
Nov 14 '05
188 17422
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote: [...]
It is not, in my opinion, a "wild extrapolation" of 7.1.4 to assume
that it could mean that any of "a value outside the domain of the
function, or a pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when the
corresponding parameter is not const-qualified" is an invalid value.


Sure it is. "Valid values" of pointer include addresses of objects
and the value NULL. Invalid values include addresses that may once
have been valid but are no longer (such as free()'d heap entries),
arbitrary integer values and other kinds of garbage.


"Valid values" of a pointer type depend on the context. As the
operand of a unary "*" operator, a null pointer is invalid; as an
argument to free() it's valid. As an argument to printf() with a "%p"
format, it's intended to be valid, but I don't see how to determine
that from the normative wording of the standard.
I would worry more about printing a stale pointer value than about a
NULL value. Are there library routines that it is safe to pass a
stale pointer to? Hardly. Are there library routines that it is safe
to pass a NULL pointer to? Of course.

printf() is by very strong implication one of the patter and might
even be the only instance of the former.


Certainly I'd *worry* more about printing a stale pointer than a null
pointer.

Even if printf("%p", ...) were defined to accept a stale pointer,
there would still be no way to pass one to it without invoking
undefined behavior just by evaluating it before the call.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #101
Keith Thompson <ks***@mib.or g> writes:
Even if printf("%p", ...) were defined to accept a stale pointer,
there would still be no way to pass one to it without invoking
undefined behavior just by evaluating it before the call.


It could be done with vprintf, though.

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

void free_print(int dummy, ...)
{
va_list ap;
va_start(ap, dummy);
free(va_arg(ap, void*));
va_end(ap);
va_start(ap, dummy);
vprintf("%p\n", ap);
va_end(ap);
}

int main(void)
{
free_print(0, malloc(1));
return 0;
}
Nov 14 '05 #102
Stephen Sprunk wrote:
"Trevor L. Jackson, III" <tl**@comcast.n et> wrote in message
news:la******** ************@co mcast.com...
I would worry more about printing a stale pointer value than about a
NULL value. Are there library routines that it is safe to pass a stale
pointer to? Hardly. Are there library routines that it is safe to pass
a NULL pointer to? Of course.

printf() is by very strong implication one of the patter and might even
be the only instance of the former.

For the former, wouldn't passing an invalid pointer to printf() invoke the
same UB that assigning it to another variable does?

For example, if this invokes UB:

void *a, *b;
a = malloc(1);
free(a);
b = a;

Then shouldn't this as well:

void *a;
a = malloc(1);
free(a);
printf("%p\n", a);

I can't conceive of how a system that legally craters on the former
(AS/400?) could work with the latter.


It probably could not. But printf()'s handling of %p/NULL could be
implementation defined.

/tj3
Nov 14 '05 #103
Keith Thompson wrote:
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote:
[...]
It is not, in my opinion, a "wild extrapolation" of 7.1.4 to assume
that it could mean that any of "a value outside the domain of the
function, or a pointer outside the address space of the program, or a
null pointer, or a pointer to non-modifiable storage when the
correspondin g parameter is not const-qualified" is an invalid value.


Sure it is. "Valid values" of pointer include addresses of objects
and the value NULL. Invalid values include addresses that may once
have been valid but are no longer (such as free()'d heap entries),
arbitrary integer values and other kinds of garbage.

"Valid values" of a pointer type depend on the context. As the
operand of a unary "*" operator, a null pointer is invalid; as an
argument to free() it's valid. As an argument to printf() with a "%p"
format, it's intended to be valid, but I don't see how to determine
that from the normative wording of the standard.


I got that impression from the fact that in general the only pointer
handling that is valid for object pointers but not valid for NULL
pointers is dereference. Some library functions explicitly forbid
NULLs, where others accept them. Perhaps the gap could be closed by
making accept/forbid a default with the other required to be explicit.


I would worry more about printing a stale pointer value than about a
NULL value. Are there library routines that it is safe to pass a
stale pointer to? Hardly. Are there library routines that it is safe
to pass a NULL pointer to? Of course.

printf() is by very strong implication one of the patter and might
even be the only instance of the former.

Certainly I'd *worry* more about printing a stale pointer than a null
pointer.


Absolutely.

Even if printf("%p", ...) were defined to accept a stale pointer,
there would still be no way to pass one to it without invoking
undefined behavior just by evaluating it before the call.


Hmmm. Clearly assigning a stale pointer to another variable would be
unacceptable. But your statement implies that:

(void)stale_ptr ;

would also be unacceptable. Is that implication accurate?

/tj3

Nov 14 '05 #104
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote:

[...]
Even if printf("%p", ...) were defined to accept a stale pointer,
there would still be no way to pass one to it without invoking
undefined behavior just by evaluating it before the call.


Hmmm. Clearly assigning a stale pointer to another variable would be
unacceptable. But your statement implies that:

(void)stale_ptr ;

would also be unacceptable. Is that implication accurate?


I believe so. The value of stale_ptr is indeterminate (C99 6.2.4p2),
meaning that it's either an unspecified value or a trap representation
(3.17.2). If it's a trap representation, reading it by an lvalue
expression that doesn't have character type invokes undefined behavior
(6.2.6.1p5).

Realistically, of course, any decent compiler will generate no code for
(void)stale_ptr ;
and the program will not trap, but that's just another possible
consequence of undefined behavior.

Digression follows.

I've been wondering why the standard says that the value of a free()d
pointer becomes indeterminate and not that it becomes a trap
representation; since evaluating it invokes undefined behavior anyway,
calling it a trap representation would be less ambiguous and no
strictly conforming program could tell the difference. But I think
I've just figured out why it's worded this way. There actually are
circumstances in which a free()d pointer can be evaluated without
invoking undefined behavior. It's sometimes possible (but not
reliably) to determine that the value of a stale pointer happens not
to be a trap representation. Here's a program that demonstrates this:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
int main(void)
{
int *ptr1, *ptr2;
ptr1 = malloc(sizeof *ptr1);
assert(ptr1 != NULL);
free(ptr1);
/*
* The value of ptr1 is now indeterminate.
* It could be either a trap representation
* or an unspecified value.
*/

ptr2 = malloc(sizeof *ptr2);
assert(ptr2 != NULL);
/*
* ptr2 has a valid value; it points to an object.
*/
printf("ptr2 = %p\n", (void*)ptr2);

/*
* Is the value of ptr1 a trap representation,
* or is it merely unspecified?
*/
if (memcmp(ptr1, ptr2, sizeof(int*)) == 0) {
/*
* The value of ptr1 is unspecified, and happens
* to be the same as the value of ptr2 (malloc()
* re-used the memory that was just free()d). We
* know ptr2 doesn't have a trap representation,
* so we can infer that ptr1 doesn't have a trap
* representation.
*/
printf("ptr1 = %p\n", (void*)ptr1);
}
else {
/*
* ptr1 may or may not have a trap
* representation; we can't reliably tell.
*/
printf("?\n");
}
return 0;
}

This is not a useful program other than as an experiment, and it's not
strictly conforming because it depends on unspecified behavior, but
it's portable and it can *sometimes* print the value of ptr1 after
it's been free()d without invoking undefined behavior. On one
implementation, the output is:

ptr2 = 0xa050248
ptr1 = 0xa050248

If the standard specified that a free()d pointer acquires a trap
representation, this program would invoke undefined behavior on
evaluating ptr1 -- and since ptr2 has the same value and
representation as ptr1, any malloc/free implementation that re-uses
addresses might impose undefined behavior on programs that use it.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #105
Keith Thompson wrote:
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote:
[...]
Digression follows.


[example and some discussion snipped]
If the standard specified that a free()d pointer acquires a trap
representation, this program would invoke undefined behavior on
evaluating ptr1 -- and since ptr2 has the same value and
representation as ptr1, any malloc/free implementation that re-uses
addresses might impose undefined behavior on programs that use it.


This poses serious implications for realloc(). At one time the
following sequence was guaranteed to return true:

char * p = malloc( 1 );
assert( p != NULL && "example purposes only" );
*p = '~';
free( p );
char *q = realloc( p, 1 );
return *q == '~';

I.e., if there were no intervening heap oprtations the most recently
free()'d block was still available *and it's contents unchanged*.

Clearly that is no longer true. But the interesting aspect of this is
that the next to last line requires that p be evaluated as part of
calling realloc(). Thus contrary to what I suggest a couple message
ago, printf is/was not the only library function that can/could handle
stale pointers.

And your example requires that ptr1 be evaluated as part of the memcmp()
with ptr2.

ISTM that trap representations for pointers should be defined as part of
the implementation rather than as part of the language. It also STM
that information about those those kinds of considerations should be
available through the compiler rather than only in the compiler's
documentation.

/tj3
Nov 14 '05 #106
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote:
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote: [...]
Digression follows.


[example and some discussion snipped]
If the standard specified that a free()d pointer acquires a trap
representation, this program would invoke undefined behavior on
evaluating ptr1 -- and since ptr2 has the same value and
representation as ptr1, any malloc/free implementation that re-uses
addresses might impose undefined behavior on programs that use it.


This poses serious implications for realloc(). At one time the
following sequence was guaranteed to return true:

char * p = malloc( 1 );
assert( p != NULL && "example purposes only" );
*p = '~';
free( p );
char *q = realloc( p, 1 );
return *q == '~';

I.e., if there were no intervening heap oprtations the most recently
free()'d block was still available *and it's contents unchanged*.


When was this guaranteed? I'm certain that it invokes undefined
behavior in C99, and I'm fairly sure that it also does so in C89/C90.
Before that, there was no standard as such. Does K&R1 make this
guarantee? (My copy is currently several thousand miles away.)

[snip]
And your example requires that ptr1 be evaluated as part of the
memcmp() with ptr2.
It doesn't evaluate ptr1 *as a pointer*. Any region of memory can be
examined as an array of unsigned char.
ISTM that trap representations for pointers should be defined as part
of the implementation rather than as part of the language. It also
STM that information about those those kinds of considerations should
be available through the compiler rather than only in the compiler's
documentation.


The standard says that trap representations may (but need not) exist,
and that evaluating something with a trap representation invokes
undefined behavior. As far as I know, that's all it says and all it
needs to say. Implementations are always free to document whatever
they like.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #107
Trevor L. Jackson, III wrote:
This poses serious implications for realloc(). At one time the
following sequence was guaranteed to return true:
Guaranteed by who? Not by a C standard, I presume?
char * p = malloc( 1 );
assert( p != NULL && "example purposes only" );
*p = '~';
free( p );
char *q = realloc( p, 1 );
return *q == '~';

I.e., if there were no intervening heap oprtations the most recently
free()'d block was still available *and it's contents unchanged*.

Clearly that is no longer true.
It may still be true, on some implementations . It may even be
documented and guaranteed by some implementors. But that doesn't change
the fact that it's undefined behaviour as far as the C standard is
concerned.
But the interesting aspect of this is
that the next to last line requires that p be evaluated as part of
calling realloc(). Thus contrary to what I suggest a couple message
ago, printf is/was not the only library function that can/could handle
stale pointers.
I know implementations where it's perfectly safe to pass a stale pointer
to memcmp(). So what? It's still undefined behaviour as far as the C
standard is concerned.
And your example requires that ptr1 be evaluated as part of the memcmp()
with ptr2.


I think he meant "memcmp( &ptr1, &ptr2, sizeof(int*) )", which evaluates
ptr1 as an lvalue but doesn't use the lvalue to read the stored value.
Nov 14 '05 #108
Keith Thompson wrote:
"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote:

"Trevor L. Jackson, III" <tl**@comcast.n et> writes:
Keith Thompson wrote:

[...]
Digression follows.


[example and some discussion snipped]

If the standard specified that a free()d pointer acquires a trap
representati on, this program would invoke undefined behavior on
evaluating ptr1 -- and since ptr2 has the same value and
representati on as ptr1, any malloc/free implementation that re-uses
addresses might impose undefined behavior on programs that use it.


This poses serious implications for realloc(). At one time the
following sequence was guaranteed to return true:

char * p = malloc( 1 );
assert( p != NULL && "example purposes only" );
*p = '~';
free( p );
char *q = realloc( p, 1 );
return *q == '~';

I.e., if there were no intervening heap oprtations the most recently
free()'d block was still available *and it's contents unchanged*.

When was this guaranteed? I'm certain that it invokes undefined
behavior in C99, and I'm fairly sure that it also does so in C89/C90.
Before that, there was no standard as such. Does K&R1 make this
guarantee? (My copy is currently several thousand miles away.)


I'm not sure about K&R, but the unix implementations did. The only
reason I know about this is that I had to emulate it when replacing
Mcrosoft's defective heap manager with an ANSI- and legacy-compatible
library in the mid 80's.

/tj3
Nov 14 '05 #109
Wojtek Lerch wrote:
Trevor L. Jackson, III wrote:
This poses serious implications for realloc(). At one time the
following sequence was guaranteed to return true:

Guaranteed by who? Not by a C standard, I presume?
char * p = malloc( 1 );
assert( p != NULL && "example purposes only" );
*p = '~';
free( p );
char *q = realloc( p, 1 );
return *q == '~';

I.e., if there were no intervening heap oprtations the most recently
free()'d block was still available *and it's contents unchanged*.

Clearly that is no longer true.

It may still be true, on some implementations . It may even be
documented and guaranteed by some implementors. But that doesn't change
the fact that it's undefined behaviour as far as the C standard is
concerned.


So realloc() is explicitly defined to not handle stale pointers? Or are
you inferring that conclusion from general language re stale pointers
and traps?
But the interesting aspect of this is that the next to last line
requires that p be evaluated as part of calling realloc(). Thus
contrary to what I suggest a couple message ago, printf is/was not the
only library function that can/could handle stale pointers.

I know implementations where it's perfectly safe to pass a stale pointer
to memcmp(). So what?


What so is that library function capable of or intended to handle stale
pointers are not unknown.
It's still undefined behaviour as far as the C
standard is concerned.
And your example requires that ptr1 be evaluated as part of the
memcmp() with ptr2.

I think he meant "memcmp( &ptr1, &ptr2, sizeof(int*) )", which evaluates
ptr1 as an lvalue but doesn't use the lvalue to read the stored value.


Probably.

/tj3
Nov 14 '05 #110

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

192
8985
by: Kwan Ting | last post by:
The_Sage, I see you've gotten yourself a twin asking for program in comp.lang.c++ . http://groups.google.co.uk/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&th=45cd1b289c71c33c&rnum=1 If you the oh so mighty programmer that you pretend to be, why don't you just write some? (And oh, void main is still not allow by the C++ standard.) Seeming as how you tried to quote the standard in an attempt to pretend you're right, I'll quote the standard to once...
6
9145
by: dam_fool_2003 | last post by:
Hai, I thank those who helped me to create a single linked list with int type. Now I wanted to try out for a void* type. Below is the code: #include<stdlib.h> #include<stdio.h> #include<string.h> #include<stddef.h> struct node
15
4163
by: Stig Brautaset | last post by:
Hi group, I'm playing with a little generic linked list/stack library, and have a little problem with the interface of the pop() function. If I used a struct like this it would be simple: struct node { struct node *next; void *data; };
3
5692
by: Jason luo | last post by:
Hi all, In c99-standard page 52,there is a sentence about void,as below: If an expression of any other type is evaluated as a void expression, its value or designator is discarded. I don't know how to understand it, How to evaluate the expression as a void expression? explicit conversion the expression? but, befor the sentence ,"implicit or explicit conversions (except to void) shall not
7
2489
by: sunglo | last post by:
My doubt comes from trying to understand how thread return values work (I know, it's off topic here), and I'm wondering about the meaning of the "void **" parameter that pthread_join expects (I think this is topical, since it's a C question, but please correct me and apologies if I'm wrong). I suppose that it's this way to allow for "generic" pointer modification, but this implies dereferencing the "void **" pointer to get a "void *"...
9
5296
by: Juggernaut | last post by:
I am trying to create a p_thread pthread_create(&threads, &attr, Teste, (void *)var); where var is a char variable. But this doesnt't work, I get this message: test.c:58: warning: cast to pointer from integer of different size. Now I thought that when it was a void I could pass anything? Thing is it works when I use an int, but in this case I wanted to use a char. It wouldnt be hard to work around it, but it annoys me because I've heard...
5
3525
by: Stijn van Dongen | last post by:
A question about void*. I have a hash library where the hash create function accepts functions unsigned (*hash)(const void *a) int (*cmp) (const void *a, const void *b) The insert function accepts a void* key argument, and uses the functions above to store this argument. It returns something (linked to the key) that the caller can store a value in. The actual key argument is always of the same pointer type (as seen in the caller,...
56
3358
by: maadhuu | last post by:
hello, this is a piece of code ,which is giving an error. #include<stdio.h> int main() { int a =10; void *p = &a; printf("%d ", *p ); //error....why should it //be an error ?can't the compiler make out because //of %d that the pointer is supposed to refer to an integer ?? or is explicit type casting required ??
27
8971
by: Erik de Castro Lopo | last post by:
Hi all, The GNU C compiler allows a void pointer to be incremented and the behaviour is equivalent to incrementing a char pointer. Is this legal C99 or is this a GNU C extention? Thanks in advance. Erik
0
9489
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9298
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10072
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
9885
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8737
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6562
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5329
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3829
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3399
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.