Предупреждение / обнаружение вычитания указателя, оба они НЕ указывают на элементы массива - PullRequest
0 голосов
/ 08 октября 2018

Для приведенного ниже фрагмента кода:

int *p = (int *)malloc(10);
int *q = (int *)malloc(10);
ptrdiff_t x = q - p;
printf("Hello World %td", x);

Я понимаю, почему компилятор не может выдать ошибку для вычитания указателя, поскольку операция не определена, а не недопустима .

Однако я не понимаю, почему я не предупреждаю о ситуации.Я пробовал VS2017, GCC 7.1.1 и Clang пока безрезультатно.

Вещи, которые я уже прошел

  1. Что именно является указателем Cесли не адрес памяти? .

  2. From, этот ответ и процитированный пункт 6.5.6 N1570 вполнеЯсно, что простое вычитание двух указателей не дает никакого значимого результата.

Для указателей на элементы массива the result is the difference of the subscripts of the two array elements @ N1570 имеет смыслпоэтому я не оспариваю законность вычитания .

Я вполне уверен, что компилятор понимает, что p и q не являются указателями на элементы массива и может легко предупредитьничего не подозревающий пользователь о проблеме.Почему они этого не делают?

Даже если они этого не делают, есть ли опция флаг / компилятор для VS, gcc или clang, которая может перехватить этот потенциальный источник ошибки?

Ни один не делает gcc -Wall -Wextra, ни /Wall в VS обнаруживают это.

1 Ответ

0 голосов
/ 08 октября 2018

Надежная проверка статическим анализатором вряд ли будет полезна в любых, кроме самых тривиальных случаях.Теперь это не означает, что GCC не предлагает вам возможность проверить правильность вашей программы в целом.Просто такие проверки требуют контрольно-измерительной аппаратуры во время выполнения и несколько дорогостоящих !Поэтому они не включены по умолчанию.

Если вы посетите документацию GCC, в разделе о «Опции программных инструментов» задокументированы следующие две полезные опции:

-fsanitize=address

Включить AddressSanitizer, быстрый детектор ошибок памяти.Инструкции по доступу к памяти предназначены для обнаружения ошибок за пределами допустимого диапазона и использования после освобождения.Опция включает -fsanitize-address-use-after-scope.См. https://github.com/google/sanitizers/wiki/AddressSanitizer для более подробной информации.На поведение во время выполнения можно влиять, используя переменную среды ASAN_OPTIONS.Если установлено значение help = 1, доступные опции отображаются при запуске инструментированной программы.См. https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags для списка поддерживаемых опций.Эта опция не может быть объединена с -fsanitize = thread.

-fsanitize=pointer-subtract

Вычитание инструмента с операндами указателя.Параметр должен быть объединен с -fsanitize = kernel-address или -fsanitize = address. Параметр не может быть объединен с -fsanitize = thread.Примечание. По умолчанию проверка отключена во время выполнения.Чтобы включить его, добавьте detect_invalid_pointer_pairs = 2 в переменную среды ASAN_OPTIONS.Использование detect_invalid_pointer_pairs = 1 обнаруживает недопустимую операцию, только когда оба указателя не равны NULL.

Теперь ваш пример является тривиальным, поэтому если мы будем следовать руководству и соответствующим образом :

export ASAN_OPTIONS=${ASAN_OPTIONS}:"detect_invalid_pointer_pairs=1"
gcc --std=c99 -Wall -pedantic -fsanitize=address -fsanitize=pointer-subtract -O0 main.c
./a.out

Вывод, полученный при запуске нашей программы, очень говорит о неопределенном поведении в вашем коде:

=================================================================
==24090==ERROR: AddressSanitizer: invalid-pointer-pair: 0x602000000030 0x602000000010
    #0 0x4008bb in main (/tmp/1539013071.1731968/a.out+0x4008bb)
    #1 0x7f8cfe10182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #2 0x4007d8 in _start (/tmp/1539013071.1731968/a.out+0x4007d8)

0x602000000030 is located 0 bytes inside of 10-byte region [0x602000000030,0x60200000003a)
allocated by thread T0 here:
    #0 0x7f8cfe5992b0 in __interceptor_malloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:86
    #1 0x4008a4 in main (/tmp/1539013071.1731968/a.out+0x4008a4)
    #2 0x7f8cfe10182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

0x602000000010 is located 0 bytes inside of 10-byte region [0x602000000010,0x60200000001a)
allocated by thread T0 here:
    #0 0x7f8cfe5992b0 in __interceptor_malloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:86
    #1 0x400896 in main (/tmp/1539013071.1731968/a.out+0x400896)
    #2 0x7f8cfe10182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: invalid-pointer-pair (/tmp/1539013071.1731968/a.out+0x4008bb) in main
==24090==ABORTING
...