Chooses an invalid undefined pointer value or implementation-specific behavior in C?

Retrieving the value of an invalid pointer is an implementation defined in C ++ in accordance with this . Now consider the following C program:

#include <stdio.h> #include <stdlib.h> int main(void) { int* p=(int*)malloc(sizeof(int)); *p=3; printf("%d\n",*p); printf("%p\n",(void*)p); free(p); printf("%p\n",(void*)p); // Is this undefined or implementation defined in behaviour C? } 

But is the same behavior in C too? Is the behavior of the above C program undefined or is the implementation defined? What does the standard C99 / C11 say? Please tell me if the behavior is different from C99 and C11.

+5
source share
4 answers

Turning to Andrew Henle:

From standard C99, 6.2.4:

The object has a storage duration that determines its lifetime. There are three storage durations: static, and automatic . Dedicated storage is described in 7.20.3. [...] The pointer value becomes undefined when the object to which it points (or has just passed) reaches the end of its life.

Then in 7.20.3.2: the standard continues to describe malloc() , calloc() and free() , noting that

The free function releases the space pointed to by ptr .

In 3.17.2:

undefined value

either vague or trap representation

In 6.2.6.1.5:

Certain representations of objects do not have to represent an object type value. If the stored value of an object has this representation and is read by an lvalue expression that does not have a character type, the behavior is undefined. [...] This representation is called traps.

Since the pointer becomes undefined, and the undefined value can be a trap representation, and you have a variable that is an lvalue value, and reading the lvalue trap view is undefined, so yes, the behavior can be undefined.

+7
source

To standard C, section 6.2.4 :

The lifetime of an object is part of the execution of the program during which it is guaranteed to be reserved for it. An object exists, has a permanent address, and retains its last stored value during its lifetime. If an object is mentioned outside its lifetime, the behavior is undefined. The value of the pointer becomes undefined when the object it points to (or just past) reaches the end of its life .

+4
source

If the compiler correctly determines that the code will inevitably be a pointer to an object that has been transferred to "free" or "realloc", even if the code does not use any object identified in this way, the Standard will not impose any requirements on what the compiler may or may not do after this point.

Thus, using a type construct:

 char *thing = malloc(1000); int new_size = getData(thing, ...whatever); // Returns needed size char *new_thing = realloc(thing, new_size); if (!new_thing) critical_error("Shrinking allocation failed!"); if (new_thing != thing) adjust_pointers(thing, new_thing); thing = new_thing; 

in most implementations, it can allow the code to retain some recalculation efforts if using realloc to reduce the allocated block does not make the block move, but there would be nothing illegal in the implementation, which unconditionally reported that the reduction in allocations failed, as if it did not fail, the code would inevitably try to compare with a pointer to a realloc'ed block. In this regard, it will also be just as legitimate (albeit less "efficient") for the implementation to keep checking if realloc returned null, but to allow arbitrary code to execute if it is not.

Personally, I see very little that can be obtained by not allowing programmers to define testing when some steps can be skipped. Skipping unnecessary code if the pointer has not changed can lead to a significant increase in efficiency when realloc is used to reduce a block of memory (this action is allowed to move the block, but in most implementations it usually will not), but this is currently fashionable for compilers apply your own aggressive optimizations that break code that tries to use such methods.

0
source

Continuing comments. I think confusion as to whether it is valid or invalid is surrounding what aspect of this index. Above is free(p); affects the starting address of the memory block pointed to by p ; it does not affect the address of p itself, which remains valid. The address p (as its value) no longer remains, leaving it undefined until reassigned. A quick example helps:

 #include <stdio.h> #include <stdlib.h> int main (void) { int *p = NULL; printf ("\n the address of 'p' (&p) : %p\n", &p); p = malloc (sizeof *p); if (!p) return 1; *p = 3; printf (" the address of 'p' (&p) : %pp points to %p with value %d\n", &p, p, *p); free (p); /* 'address of p' unchanged, p itself indeterminate until reassigned */ printf (" the address of 'p' (&p) : %p\n\n", &p); p = NULL; /* p no longer indeterminate and can be allocated again */ return 0; } 

Output

 $ ./bin/pointer_addr the address of 'p' (&p) : 0x7fff79e2e8a0 the address of 'p' (&p) : 0x7fff79e2e8a0 p points to 0x12be010 with value 3 the address of 'p' (&p) : 0x7fff79e2e8a0 

The address p does not change either using malloc or free . The value of p executed (or rather, the address p stored as a value). After free , the address p stores is freed in the system and can no longer be accessed via p . Once you explicitly reassign p = NULL; p , it is no longer indefinite and can be used to highlight again.)

-2
source

Source: https://habr.com/ru/post/1235423/


All Articles