Когда выбрасывается сегфо? - PullRequest
1 голос
/ 14 октября 2010

Предположим, у меня есть класс, подобный

class A {
    int x;
    int y;
  public:
    getSum1() const {
        return getx() + y;
    }
    getSum2() const {
        return y + getx();
    }
    getx() const {
        return x;
    }
}

И затем у меня есть

int main(int argc, char **argv) {
    A *a = 0;
    switch(argc) {
    case 0:
        a->getsum1();
        break;
    default:
        a->getsum2();
        break;
    }
    return 1;
}

Эта программа будет работать с ошибкой.Я заметил, что на моей машине, когда выполняется getsum1, дамп ядра сообщает, что segfault вызвана в getx, а при выполнении getsum2 говорит, что ошибка произошла в getsum2.

Это имеет смысл.У меня есть 2 вопроса:
1. указано ли это поведение или оно зависит от реализации?
И самое главное:
2. Может ли дамп ядра сказать, что segfault произошел в main, когда была разыменована a?(т.е. в a-> getsum *)

Спасибо.

Ответы [ 5 ]

1 голос
/ 14 октября 2010

Когда вы вызываете эти функции по нулевому указателю, вы получаете неопределенное поведение . Это действительно все, что следует сказать; все может случиться, не делай этого.

Причина, по которой он segfaults, заключается в том, что в нуле нет A. Попытка получить доступ к этим членам пытается получить доступ к неверному адресу. (Это происходит в getx и getSum2, отсюда и отчет о сбое.)

Нет, нельзя сказать, что segfault произошла в main, потому что в main не было доступа к null. (Вы все еще вводили неопределенное поведение в main, без сомнения, но на практике он просто вызывал функцию с this, установленным в null.) Вы получили доступ к нему в этих функциях. На практике, если функция никогда не использует this, она не завершится с нулевым указателем.

Но не надо.

0 голосов
/ 07 октября 2015

"Когда бросают сегфо?" Иногда бросается никогда , когда должно быть брошено. Основой большинства реализаций является операционная система с защитой памяти . Когда ОС отсутствует (встроена), или очень проста (CP / M, DOS), или имеет «низкопрофильную» цель (встроена), или у ЦПУ нет такой функциональности (<80186), проблема скрыта или задержана. Это очень плохие новости. <em>Хьюстон, у нас БОЛЬШАЯ невидимая проблема.

Примечание: C ++ в защищенной среде может реализовывать сценарии, когда проблема также скрыта (указатель плох, но в допустимой области)

Общее правило, как понимать C / C ++, является ключевым «неопределенное поведение» (как говорят многие ответы), иногда такое исключение

0 голосов
/ 14 октября 2010

Две важные вещи:

  1. У вас неопределенное поведение, потому что a равно нулю. Неопределенное поведение означает, что что-нибудь идет, стандарт C ++ не накладывает никаких ограничений на программу с неопределенным поведением.

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

    * 1017.

0 голосов
/ 14 октября 2010

К тому времени, когда происходит coredump, вы уже не в C ++.Некоторые операторы в скомпилированном коде вызывали плохие вещи, такие как попытка доступа к неверному адресу памяти, в вашем случае через нулевой указатель.

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

Дело в том, что возврат от скомпилированных двоичных файлов к строкам исходного кода несколько сложен, поскольку в языке есть множество возможностей длянекоторый "как будто" вид переупорядочения заявлений и другой хитрости.

Таким образом, сам C ++ в спецификации языка не будет указывать то, что вам скажет дамп ядра, и, как уже наблюдалось, явно дает недопустимое поведение при разыменовании нулевых указателей.

Дело в том, что я не думаю, что это имеет большое значение.Для такого рода ошибок получение «достаточно близкого» показателя того, где проблема в скором времени, приводит к источнику проблемы.Более неприятными являются проблемы повреждения кучи, возникающие в тех случаях, когда симптомы и причины могут находиться на расстоянии нескольких шагов друг от друга, а дампы ядра используются меньше.

0 голосов
/ 14 октября 2010

Вызов доступа к членам и вызов функций-членов по нулевым указателям является неопределенным поведением.

Segfault происходит, когда программа пытается получить доступ к x или y, поэтому это происходит в первом getx () и getSum2 () во втором.

...