This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c/63303] New: Pointer subtraction is broken when using -fsanitize=undefined


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303

            Bug ID: 63303
           Summary: Pointer subtraction is broken when using
                    -fsanitize=undefined
           Product: gcc
           Version: 4.9.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: mikulas at artax dot karlin.mff.cuni.cz
              Host: x86_64-linux-gnux32
            Target: x86_64-linux-gnux32
             Build: x86_64-linux-gnux32

The undefined behavior sanitizer incorrectly warns about pointer subtraction.

The reason is that the undefined behavior sanitizer treats pointer subtraction
like subtraction of two signed integers and warns if it would result in integer
overflow. However, this logic is incorrect.

Subtracting of these two pointers is perfectly legal operation but it results
in incorrect warning: (char *)0x90000000 - (char *)0x70000000: this bug causes
spurious warnings in correct program if array spans the boundary 0x80000000 and
the program subtracts pointers in this array.

Subtracting these two pointers doesn't result in a warning, but it should
because the resulting integer overflows: (char *)0xc0000000 - (char
*)0x30000000

BTW. The sanitizer also lacks warnings when addition of a pointer and integer
results in overflow. For example (char *)0xd0000000 + 0x40000000U doesn't
result in a warning but it should.

This is the example code, compile it with -fsanitize=undefined

#include <stdio.h>
#include <stddef.h>

__attribute((noinline,noclone)) ptrdiff_t ptr_diff(char *p1, char *p2)
{
        return p1 - p2;
}

__attribute((noinline,noclone)) void *ptr_add(char *p1, unsigned long p2)
{
        return p1 + p2;
}

void *get_address(unsigned n)
{
        return (void *)((unsigned long)n << (sizeof(void *) * 8 - 4));
}

int main(void)
{
        printf("%ld\n", (long)ptr_diff(get_address(0x9), get_address(0x7))); /*
sanitizer should not warn here */
        printf("%ld\n", (long)ptr_diff(get_address(0xc), get_address(0x3))); /*
sanitizer should warn here */
        return 0;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]