Могу ли я заставить gcc обнаружить ВСЕ неопределенное поведение? - PullRequest
0 голосов
/ 19 апреля 2019

Есть ли способ заставить gcc обнаружить все неопределенное поведение? Я хочу, чтобы он обнаруживал обе вещи, которые можно обнаружить во время компиляции и во время выполнения. Я знаю, что UB полезен как для упрощения создания компиляторов, так и для того, чтобы компилятор мог оптимизировать код. Последнее не имеет значения, когда вы отлаживаете, и потребность в легких компиляторах не так велика, как это было в 1972 году. Более того, gcc на данный момент является очень зрелым компилятором, и если бы это было возможно, он бы сильно испортил отладку проще.

Я знаю, что -Wformat выдаст предупреждение для printf("%d", 42) и для неинициализированных переменных. Параметр -Warray-bounds может перехватывать, когда вы пытаетесь получить доступ к памяти вне массива, хотя мне нужно было поработать над созданием кода, который фактически выдает предупреждение. Я также знаю, что некоторые ошибки во время выполнения могут быть обнаружены с помощью -fstack-protector-all.

Так что мой вопрос просто так. Есть ли способ гарантировать , что все UB будут обнаружены, либо при компиляции, если это возможно, но самое позднее, когда это произойдет во время выполнения?

Ответы [ 3 ]

6 голосов
/ 19 апреля 2019

Это невозможно.Обнаружение неопределенного поведения может буквально потребовать решения проблемы остановки;например, кавычка C11 6.8.5 :

6 Оператор итерации, управляющее выражение которого не является константным выражением, не выполняет операций ввода / вывода, не получает доступ к энергозависимым объектами не выполняет синхронизацию или атомарные операции в своем теле, управляющем выражении или (в случае оператора for) своего выражения-3, может быть реализовано реализацией для завершения.

C isне предназначен для облегчения обнаружения ошибок.

2 голосов
/ 19 апреля 2019

Это в принципе невозможно.Учтите, что некоторые UB могут очень сильно зависеть от данных времени выполнения.

Если вы попросите своего пользователя ввести значение во время выполнения, а затем использовать это значение в качестве указателя (или для вычисления указателя), к которому вы обращаетесь инаписать через, как вы обнаружите, запись будет вызывать UB или нет?Вы можете проверить образ процесса и посмотреть, не приведет ли запись к ошибке сразу, но если этого не произойдет, то как вы обнаружите, что запись не была в месте, которое вызовет эффект бабочки, который в конечном итоге приведет к ошибкеили выполнение непреднамеренного кода?

Это также не должно касаться указателей.Вы можете анализировать быстрее, если предположите, что все входные данные правильно сформированы (без проверки ошибок при неправильном вводе), но если вы затем проанализируете неправильный файл, все может произойти так же, как в примере с указателем.

0 голосов
/ 24 апреля 2019

Представьте себе этот пример (предположим, что у нас есть некоторый класс BigInteger произвольной точности и функция random_big_int, которая возвращает положительное целое число n с вероятностью 1/2^n)

void compute_collatz(BigInteger x) {
    while (x != 1) {
        if (x % 2) {
            x = 3*x + 1;
        } else {
            x = x / 2;
        }
    }
    std::cout << "Terminated successfully!" << std::endl;
}

int main() {
    BigInteger x = random_big_int();
    compute_collatz(x);
}

Если Гипотеза Коллатца неверна, она может войти в бесконечный цикл без побочных эффектов (если выбрано случайное целое число, для которого гипотеза ложна), что является неопределенным поведением.

Итак, чтобыСкажите, может ли это вызвать UB, компилятор должен знать, верна ли гипотеза Коллатца, что является открытой проблемой в математике.

...