Вызов strndup обрезает стековые фреймы
Я видел странное поведение при вызове "strndup" в AIX 5.3 и 6.1. Если я вызываю strndup с размером, превышающим размер фактической длины строки источника, то после этого вызова происходит повреждение стека.
Ниже приведен пример кода, где может возникнуть эта проблема:
int main ()
{
char *dst_str = NULL;
char src_str[1023] = "sample string";
dst_str = strndup(src_str, sizeof(src_str));
free(dst_str);
return 0;
}
Кто-нибудь испытывал такое поведение?
Если да, пожалуйста, дайте мне знать.
По моим наблюдениям, должен быть патч от ОС, где эта проблема была исправлена. но я не смог бы получить этот патч, если он вообще есть. Пожалуйста, пролейте немного света.
Спасибо и С уважением, Thumbeti
4 ответа
Вам не хватает #include <string.h>
в вашем коде. Пожалуйста, попробуйте это - я уверен, что это сработает. Причина в том, что без #include <string.h>
нет прототипа для strndup()
в области видимости, поэтому компилятор предполагает, что strndup()
возвращает int
и принимает неопределенное количество параметров. Это явно неправильно. (Я предполагаю, что вы компилируете в POSIX-совместимом режиме, поэтому strndup()
доступно для вас.)
По этой причине всегда полезно компилировать код с включенными предупреждениями.
Если ваша проблема сохраняется даже после изменения, возможно, есть ошибка.
Изменить: похоже, что может быть проблема с strndup()
на AIX: проблема, кажется, в сломанной strnlen()
функция в AIX. Если даже после #include <string.h>
вы видите проблему, скорее всего, вы видите ошибку. Поиск в Google показывает длинный список результатов по этому поводу.
Изменить 2:
Можете ли вы попробовать следующую программу и опубликовать результаты?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char *test1 = "abcdefghijabcdefghijabcdefghijk";
char *test2 = "012345678901234567890123456789";
char *control = "01234567890123456789012345678";
char *verify;
free(strndup(test1, 30));
verify = strndup(test2, 29); /* shorter then first strndup !!! */
fprintf(stderr,">%s<\n",verify);
if (strcmp(control, verify))
printf("strndup is broken\n");
}
(Взято из https://bugzilla.samba.org/show_bug.cgi?id=1097.)
Изменить 3: После просмотра вашего вывода, который >01234567890123456789012345678<
и без strndup is broken
Я не думаю, что ваша версия AIX имеет strndup
ошибка.
Скорее всего, вы где-то повреждаете память (учитывая тот факт, что проблема возникает только в большой программе при определенных условиях). Можете ли вы сделать небольшой, полный, компилируемый пример, демонстрирующий проблему повреждения стека? В противном случае вам придется отладить выделение / освобождение памяти в вашей программе. Есть много программ, которые помогут вам сделать это, таких как valgrind, glibc mcheck, dmalloc, electricfence и т. Д.
Старая тема, но я тоже столкнулся с этой проблемой. Простая тестовая программа в AIX 6.1 в сочетании с MALLOCDEBUG AIX подтверждает проблему.
#include <string.h>
int main(void)
{
char test[32] = "1234";
char *newbuf = NULL;
newbuf = strndup(test, sizeof(test)-1);
}
Скомпилируйте и запустите программу с обнаружением переполнения буфера:
~$ gcc -g test_strndup2.c
~$ MALLOCDEBUG=catch_overflow ./a.out
Segmentation fault (core dumped)
Теперь запустите dbx для анализа ядра:
~$ dbx ./a.out /var/Corefiles/core.6225952.22190412
Type 'help' for help.
[using memory image in /var/Corefiles/core.6225952.22190412]
reading symbolic information ...
Segmentation fault in strncpy at 0xd0139efc
0xd0139efc (strncpy+0xdc) 9cc50001 stbu r6,0x1(r5)
(dbx) where
strncpy() at 0xd0139efc
strndup@AF5_3(??, ??) at 0xd03f3f34
main(), line 8 in "test_strndup2.c"
Просматривая инструкции в strndup, кажется, что он размещает буфер, достаточно большой для обработки строки в s плюс терминатор NULL. Однако он всегда будет копировать n символов в новый буфер, дополняя нулями при необходимости, вызывая переполнение буфера, если strlen(s) char* strndup(const char*s, size_t n)
{
char* newbuf = (char*)malloc(strnlen(s, n) + 1);
strncpy(newbuf, s, n-1);
return newbuf;
}
Алок прав. и с помощью gcc toolchain под glibc вам нужно определить _GNU_SOURCE, чтобы получить decl из strndup, иначе это не decl'd, например:
#include <string.h>
...
compilo:
gcc -D_GNU_SOURCE a.c
Большое спасибо за ваши быстрые ответы. Я попробовал данную программу.
следующий результат:
bash-2.05b# ./mystrndup3
>01234567890123456789012345678<
В моей программе, которую я включил, проблема все еще сохраняется. Ниже приведено объявление strndup в предустановленном коде.
extern char * strndup(const char *, size_t);
Я хотел бы уточнить одну вещь, с небольшой программой я не получаю эффект повреждения стека. Это постоянно появляется в моем продукте, который имеет огромное количество вызовов функций.
Использование strndup следующим образом решило проблему:
dst_str = strndup(src_str, srtlen(src_str));
Обратите внимание: вместо sizeof используется strlen, так как мне нужна только правильная строка. Я пытаюсь понять, почему это происходит.
Поведение, которое я вижу с моим продуктом, когда я использую strndup с большим размером:
- На "выходе" из основного, казнь сопровождается "незаконным указанием"
- периодически "Illegal Instruction" в середине выполнения (после вызова strndup).
- Повреждение некоторой выделенной памяти, которая нигде не связана с strndup.
Все эти проблемы решаются простым изменением использования strndup с реальным размером исходной строки.
Спасибо и С уважением, Thumbeti