Справка по проблеме с дампом ядра, связанной с классом строки - PullRequest
2 голосов
/ 11 марта 2011

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

(gdb) bt
#0 in strlen () from /lib/libc.so.6
#1 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string$base () from libstdc++.so.6
#2 in CustomStr::CustomStr()

Код имеет класс-оболочку над классом Std :: String, что-то вроде:

class CustomStr: public string
{
    //Some custom members here

};

This custom class has constructors:
CustomStr::CustomStr(const char *str):string(str)
{
   //Some derived class inits
}

CustomStr::CustomStr(const CustomStr& str) : string(str.c_str())
{
    //Some derived class inits   
}

Я думаю, что оба этих конструктора имеют проблему: если передается указатель на NULL, то же самое передается в конструктор String, и когда он внутренне вызывает strlen () для определения длины, произойдет Undefined Behavior (UB). Я думаю, что правильным способом реализации будет проверка на NULL перед вызовом строкового конструктора, например:

CustomStr::CustomStr(const char *str)
{
   if(str!= NULL)
       string(str);
   //Some derived class inits
}

CustomStr::CustomStr(const CustomStr& str)
{
    if(str!= NULL)
       string(str.c_str());
    //Some derived class inits   
}

У меня есть следующие вопросы:

  1. Кажется ли проблема (которую я считаю) и предлагаемое решение обоснованным?
  2. Проверяет ли строковый конструктор значение NULL? Я думаю, что должно, потому что внутренне он вызывает strlen (), который покажет UB на NULL.
  3. Помимо проверки NULL Как можно проверить, передается ли действительный const char *? (NOn NULL прекращается const char * и т. Д.)

Ответы [ 5 ]

2 голосов
/ 11 марта 2011

Стандарт C ++ требует, чтобы указатель, переданный в std::string(const char*), не был нулевым указателем (§21.4.2 в c ++ 0x draft n3092). Таким образом, сам строковый класс не будет проверять это условие, и передача значения NULL означает, что ваш код не соответствует.

Вы исправляете для CustomStr(const char*) выглядит нормально, но для CustomStr(const std::string&) нет. Ссылка не может быть нулевой. (Я был бы удивлен, если это вообще скомпилировано.)

Теперь есть способ проверить, является ли случайный char* "допустимым", за исключением проверки на нуль.

2 голосов
/ 11 марта 2011

Конструктор из const char * не проверяет нулевой указатель, он должен проверить вызывающего, если это необходимо. ВЫ должны знать, возможно ли или нет нулевое значение аргумента.

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

1 голос
/ 11 марта 2011

Дальнейшее изучение дампа ядра должно дать вам довольно точное представление о том, что вызвало сбой.В частности, какое именно исключение выдается?Если это нарушение прав доступа (он же segfault), то дамп должен также точно указать, к какому неверному адресу осуществляется доступ, что, в свою очередь, скажет вам, является ли ваша проблема чтением из указателя NULL или чем-то еще.

Вполне вероятно, что указатель NULL на константу std::string может быть вашей проблемой, но вы не должны просто предполагать это - цель дампа ядра состоит в том, чтобы извлечь догадки из такой отладки.

В любом случае, да, std::string просто взорвется, если вы создадите его из NULL-указателя, и поэтому вы должны проверять NULL любые указатели перед тем, как передать их в строковый конструктор. Например, ,

class CustomStr : public string
{
  CustomStr(const char *str) : string( str ? str : "<INVALID>" ) { .. }  
};

будет одним простым обходным путем.

0 голосов
/ 11 марта 2011

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

Может быть, это не та проблема, которая у вас есть, но это хорошо знать. Не делай этого.

Вы можете использовать std :: string в качестве композиции из вашего класса-оболочки. Или, как я обнаружил, вообще не используйте никакой оболочки для класса std :: string, которая приводит к большему количеству проблем, а не к решению некоторых.

Вы можете использовать некоторые внешние функции, если вам нужны определенные функции, такие как «обрезка» и т. Д.

Хорошо знать, что в буст-библиотеке существует множество функций для работы со строками.

0 голосов
/ 11 марта 2011

Аргумент к std :: string (const char *) должен быть указателем на строку с \ 0-завершенной строкой.NULL ни на что не указывает и, конечно, не является строкой с нулевым символом в конце.Таким образом, нарушение условия является пропуском NULL.

Отладочная сборка должна утверждать, что указатель не равен NULL, потому что std::string - это класс, который будет использоваться новичками.Его не следует проверять во время выполнения, поскольку ни одна действительная программа все равно не пропустит NULL.

Как обычно в C ++, нет способа проверить , является ли указатель «действительным».C ++ понесет значительные потери производительности, если будет обязательным механизм, который мог бы ответить на этот вопрос.

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