Обнаружение переполнения строки в C

Мы используем DevPartners для проверки утечек памяти. Он делает замечательную работу, хотя и не находит переполнения строк, как показано ниже

char szTest [1] = "";

for (i = 0; i < 100; i ++) {

    strcat (szTest, "hi");
}

Вопрос-1: Есть ли какой-нибудь способ, которым я могу заставить BoundsChecker это обнаружить?

Вопрос-2: Есть ли у них какой-либо другой инструмент, который может обнаружить такие проблемы?

8 ответов

Решение

Я попробовал это в моем devpartner (msvc6.6) (devpartner 7.2.0.372)

Я подтверждаю ваше наблюдаемое поведение. Я получаю нарушение доступа после примерно 63 проходов цикла.

Что Compuware должен сказать о проблеме?

CppCheck обнаружит эту проблему.

valgrind обнаружит запись прошлых динамически распределенных данных, но я не думаю, что это можно сделать для автоматических массивов, как в вашем примере. Если вы используете strcat, strcpyи т. д., вы должны убедиться, что место назначения достаточно велико.

Редактировать: я был прав насчет Вальгринда, но есть надежда:

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

Однако экспериментальный инструмент Ptrcheck может обнаруживать подобные ошибки. Запустите Valgrind с --tool=exp-ptrcheck Вариант, чтобы попробовать это, но будьте осторожны, что это не так надежно, как Memcheck.

Я не использовал Ptrcheck.

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

#define strcpy  strcpy_is_banned_use_strlcpy
#define strcat  strcat_is_banned_use_strlcat
#define strncpy strncpy_is_banned_use_strlcpy
#define strncat strncat_is_banned_use_strlcat
#define sprintf sprintf_is_banned_use_snprintf

Поэтому любые попытки использования "запрещенных" подпрограмм приведут к ошибке компоновщика, которая также скажет вам, что вы должны использовать вместо этого. MSVC сделал нечто подобное, что можно контролировать с помощью макросов, таких как _CRT_SECURE_NO_DEPRECATE,

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

Вы можете обнаружить, что ваш компилятор может помочь. Например, в Visual Studio 2008 проверьте свойства проекта - C/C++ - Страница генерации кода. Есть опция "Проверка безопасности буфера".

Я предполагаю, что он резервирует немного дополнительной памяти и записывает в нее известную последовательность. Если эта последовательность изменяется, она предполагает переполнение буфера. Я не уверен, хотя - я помню, что читал это где-то, но я точно не помню, было ли это про VC++.

Если вы включите переключатель компилятора /RTCs, это может помочь в обнаружении подобных проблем. С этим включением тест вызвал нарушение прав доступа при запуске strcat только раз.

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

Учитывая, что вы пометили этот C++, зачем вообще использовать указатель на char?

std::stringstream test;
std::fill_n(std::ostream_iterator<std::string>(test), 100, "hi");

Проблема заключалась в том, что по умолчанию подсистема проверки API не включена, и сообщения, которые вас интересовали, приходят оттуда.

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

Результаты: 100 сообщений о переполнении записи в локальную переменную и 99 сообщений о том, что строка назначения не имеет нулевого значения, завершена. Технически, это второе сообщение неверно, но BoundsChecker ищет только нулевое завершение в границах самой строки назначения, и после первого вызова strcat оно больше не содержит нулевой байт в своих границах.

Отказ от ответственности: я работаю на MicroFocus как разработчик, работающий над BoundsChecker.

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

Другие вопросы по тегам