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

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

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

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

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