[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