[cfe-dev] Relational operators on pointers

Eli Friedman eli.friedman at gmail.com
Wed Oct 12 13:19:58 PDT 2011


On Wed, Oct 12, 2011 at 1:29 AM, Stefan Marr
<mailinglists at stefan-marr.de> wrote:
> Hi:
>
> I got a problem with C++ semantics.
>
> As far as I understand from the standard (Sec. 5.9) and various discussions on comp.std.c++ the use of >=, < etc. is not generally defined for pointers.
>
> However, it says, it should be defined for pointers on the same array.
>
> So, what I would expect to work is a comparison of char* >= char* in any circumstances.
> No matter from where I obtain those pointers.
>
> My situation is an interpreter implementation with a fixed heap of 2GB size in a 32bit program.
>
> The heap is allocated with mmap. The example snippet is given below.
> `read_mostly_memory_base` and so on are defined as char*.
>
> When the test started failing after switching from GCC 4.2 to LLVM-GCC 4.2 and later Clang, I tried to compensate for that with casting the pointers to uintptr_t.
> The reason for that was, that from my testing, I concluded that the compiler treats the pointer values as signed integers. This causes problems, since with a heap of 2GB, we obviously reach into address with the 32nd bit/sign bit set.
>
> And indeed, masking and testing the sign bit explicitly allows me to distinguish these cases.
> However, all kind of casts to unsigned integers did not have any observable effect.
>
> So, my question now is, how can I make sure that all pointer comparisons are treated as interpreting the memory address as an unsigned 32bit value?
> As you can imagine, there are quite a couple of relational tests all over the place in our code base.
>
>
> Here the code in question:
>
> void Memory_System::map_read_write_and_read_mostly_memory(int pid,
>                                                          size_t total_read_write_memory_size,
>                                                          size_t total_read_mostly_memory_size) {
>  read_mostly_memory_base     = map_heap_memory(total_read_mostly_memory_size + total_read_write_memory_size,
>                                                pid,  MAP_SHARED);
>  read_mostly_memory_past_end = read_mostly_memory_base + total_read_mostly_memory_size;
>
>  read_write_memory_base      = read_mostly_memory_past_end;
>  read_write_memory_past_end  = read_write_memory_base  + total_read_write_memory_size;
>
>  if (On_Tilera) {
>    mark_incoherent(read_mostly_memory_base, total_read_mostly_memory_size);
>  }
>
>  if (read_write_memory_base >= read_write_memory_past_end) {
>    unlink(mmap_filename);
>    fatal("begining should be before the end");
>  }
>
>  /* Make sure that the addresses are layed out as expected:
>               read-mostly heap first, then read/write heap */
>  if (read_mostly_memory_base >= read_write_memory_past_end) {
>    printf("grand_total: %lu, read_mostly_memory_base: 0x%llx, read_mostly_memory_past_end: 0x%llx\n"
>           "                       read_write_memory_base:  0x%llx, read_write_memory_past_end:  0x%llx\n",
>           total_read_write_memory_size + total_read_mostly_memory_size,
>           (u_int64_t)read_mostly_memory_base, (u_int64_t)read_mostly_memory_past_end,
>           (u_int64_t)read_write_memory_base,  (u_int64_t)read_write_memory_past_end);
>    unlink(mmap_filename);
>    fatal("contains will fail");
>  }
> }
>
> On more thing: I also looked at what the Clang produces with -O4 -S for that case, and that actually does not reflect my earlier conclusion but makes me even more confused.
> Perhaps someone can explain me why the mark parts (with !!) are valid.

The transformation in question is assuming a single memory allocation
is less than 2GB for 32-bit code.  That's usually correct, but I guess
it isn't in your case.  IIRC, -fwrapv will force the compiler to do
what you want here.

-Eli




More information about the cfe-dev mailing list