вызов strndup обрезает стековые фреймы - PullRequest
2 голосов
/ 19 января 2010

Я видел странное поведение при вызове "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;
}

Кто-нибудь сталкивался с таким поведением?

Если да, сообщите мне.1009 * По моим наблюдениям, должен быть патч от ОС, где эта проблема была исправлена.но я не смог бы получить этот патч, если он вообще есть.Пожалуйста, пролите немного света.

Спасибо и С уважением, Thumbeti

Ответы [ 4 ]

5 голосов
/ 19 января 2010

Вам не хватает #include <string.h> в вашем коде.Пожалуйста, попробуйте это - я уверен, что это сработает.Причина в том, что без #include <string.h> нет прототипа для strndup() в области видимости, поэтому компилятор предполагает, что strndup() возвращает int и принимает неопределенное количество параметров.Это явно неправильно.(Я предполагаю, что вы компилируете в режиме POSIX-совместимого, поэтому вам доступен strndup().)

По этой причине всегда полезно компилировать код с включенными предупреждениями.

Если ваша проблема не устраняется даже после изменения, возможно, есть ошибка.

Редактировать : похоже, может возникнуть проблема с strndup() в AIX:Кажется, проблема в сломанной функции strnlen() в AIX.Если даже после #include <string.h> вы видите проблему, скорее всего, вы видите ошибку.A Поиск 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#c10.)

Редактировать 3 : после просмотра вашего вывода, которое составляет >01234567890123456789012345678<, и без strndup is broken, яне думайте, что ваша версия AIX содержит ошибку strndup.

Скорее всего, вы где-то повреждаете память (учитывая тот факт, что проблема возникает только в большой программе при определенных условиях).маленький, полный, компилируемый пример, который демонстрирует проблему повреждения стека? В противном случае вам придется отлаживать выделение / освобождение памяти в вашей программе. Есть много программ, которые помогут вам сделать это, таких как valgrind , glibc mcheck , dmalloc , электрический забор и т. Д.

2 голосов
/ 22 августа 2012

Старая тема, но я тоже столкнулся с этой проблемой. Простая тестовая программа в 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;
}
1 голос
/ 19 января 2010

Алок прав. и с помощью gcc toolchain под glibc вам нужно будет определить _GNU_SOURCE, чтобы получить decl из strndup, иначе это не decl'd, например:

#include <string.h>
...

compilo:

gcc -D_GNU_SOURCE a.c
0 голосов
/ 19 января 2010

Большое спасибо за ваши быстрые ответы. Я попробовал данную программу.

следующий результат:

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 с большим размером:

  1. На «выходе» из main выполнение выполняется с «недопустимой инструкцией»
  2. периодически "Недопустимая инструкция" в середине выполнения (после вызова strndup).
  3. Повреждение некоторой выделенной памяти, которая не относится к strndup.

Все эти проблемы решаются простым изменением использования strndup с реальным размером исходной строки.

Спасибо и С уважением, Thumbeti

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