News for hackers. Stuff that matters.
Re:GCC's new fortification level: The gains and costs by kazinator on Sunday September 18, 2022 @11:59PM (#32894137)
You can use memcmp to check whether the pointer has not changed.

   void *oldptr = malloc(73);
   void *newptr = realloc(oldptr, 42);

   if (memcmp(&oldptr, &newptr, sizeof oldptr) == 0) {
     // not changed
   }
The value of oldptr is indeterminate if it is used as a pointer; it can still be accessed as an array of bytes.
Re:GCC's new fortification level: The gains and costs by amadvance on Monday September 19, 2022 @03:33AM (#32895401)
Is a cast to uintptr_t also OK ?

  void *oldptr = malloc(73);
  uintptr_t savedptr = (uintptr_t)oldptr;
  void *newptr = realloc(oldptr, 42);
  if (savedptr == (uintptr_t)newptr) {
    // not changed
  }
Re:GCC's new fortification level: The gains and costs by munch117 on Monday September 19, 2022 @12:49PM (#32900776)
That is OK, at least in the sense that there's no undefined behaviour.

I'm not sure it's also OK, because the memcmp suggestion you are replying to seems a bit suspect.

There's still the problem that comparing the uintptr_t's is not guaranteed to yield the same result as the pointers they were cast from. But that's merely implementation-specific behaviour, not undefined.

Re:GCC's new fortification level: The gains and costs by kazinator on Monday September 19, 2022 @02:52PM (#32902331)
I think it's fine on the assumption that a uintptr_t converted from a pointer cannot be a trap representation, which is the case on mainstream platforms.

(An unsigned type can only have trap patterns if it has padding bits. Every combination of the value bits is a valid value according to the pure binary encoding.)

Re:GCC's new fortification level: The gains and costs by amag on Monday September 19, 2022 @09:19AM (#32897911)
ASFAIU the problem was that the application in question kept using oldptr, e.g.:

   int *oldptr = (int *)malloc(42);
   int *newptr = (int *)realloc(oldptr, 73);

   if (oldptr == newptr) {
     newptr[70] = 10; // ok because the "object" newptr can contain 73 ints
     oldptr[70] = 10; // SIGABRT here because the "object" oldptr can only contain 42 ints even though the memory block oldptr points to can hold 73
   }
Re:GCC's new fortification level: The gains and costs by rurban on Monday September 19, 2022 @02:44AM (#32895066)
wrong. you need to save away old ptr and assign to the realloc 1st arg. memcmp is also wrong, compare the values, so that the compiler knows about it.

    void *ptr = malloc(73);

    void *old = ptr;
    void *ptr = realloc(ptr, 42);
    bool realloced = old != ptr;
Re:GCC's new fortification level: The gains and costs by kazinator on Monday September 19, 2022 @02:53AM (#32895122)
I don't quite see what you're getting at, but I do know you can't declare ptr twice in the same scope in C; did you miss a curly brace somewhere to open a new scope, or else want to use different names?

Not comparing the values is the point. Your code uses the pointer that was passed to realloc, and that is undefined behavior according to ISO C.

The game you're playing with the identifiers is pointless; there is no difference between what you're trying to do and just:

   void *oldptr = malloc(73);
   void *newptr = realloc(oldptr, 42);
   bool realloced = oldptr != newptr; // undefined behavior
That's what the article is referring to, and that I'm specifically addressing with the memcmp. Accessing the pointer as an array of bytes doesn't use its value as a pointer. Bytes cannot be indeterminate; they are not allowed to have trap representations.

(There could be a false negative: the address didn't change, but the pointer bit pattern did. On 64 bit systems, the C library could easily put a tag into the upper bits of the pointer, and have realloc change the tag even if the address is the same.)

The problem described in the article is that the compiler generated a false negative even when the pointer didn't change, due to the undefined behavior. The idea is something like that since oldptr was passed to realloc, it is garbage. The newptr is good, and we need not compare garbage to non-garbage; we can just declare them to be unequal.

That's what you might get if your follow your advice of "compare the values, so that the compiler knows about it".