Поведение стека Strcat

При запуске следующего преднамеренного кода разрушения стека strcat копирует значение источника ровно десять раз.

#include <stdio.h>
#include <stdlib.h>

int main() {
    char a[16];
    char b[16];
    char c[32];

    strcpy(a, "abcdefghijklmnop");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(b, "ABCDEFGHIJKLMNOP");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcat(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    return 0;
}

Выход:

a = abcdefghijklmnop b = c =

a = abcdefghijklmnopABCDEFGHIJKLMNOP b = ABCDEFGHIJKLMNOP c =

a = abcdefghijklmnopABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP b = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP c = ABCDEFGHIJKLMNOP

а = abcdefghijklmnopABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP Ь = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP с = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP

** Обнаружено разрушение стека *:./strcpytest прекращено

Параметры здания:

gcc -O0 -g3 -Wall -c -fmessage-length = 0

Код выполняется на архитектуре x86_64.

Почему он соединяется только десять раз?

3 ответа

Решение

Поведение strcpy() и strcat() не определено для перекрывающихся строк. Поэтому обе ваши записи в c[] являются подозрительными, и вместо того, чтобы просто тестировать разрушение стека, вы также тестируете обработку вашего компилятора этого неопределенного поведения.

Я ожидаю, что строка strcpy(c, b) потерпит неудачу, но реализация должна каким-то образом получить длину b, прежде чем она перезапишет конечный ноль в начале c. Это может произойти, если он копирует, например, из последнего байта в первый.

strcat (c, b) может быть реализован более простым способом. Может быть, десятикратных данных достаточно, чтобы достичь определенного предела, который его прекращает.

Если вы хотите просто проверить повреждение стека, не используйте эти методы. Вместо этого просто используйте один массив и запишите за его конец цикл, например, "for (i = 0; i < 1000000; i++) c[i] = 'h';"

Если ваша платформа использует защиту памяти и ее стек стекает вниз, например, x86 ( Каково направление роста стека в большинстве современных систем?), Выбирает любую позицию стека и записывает оттуда увеличивающиеся адреса (например, для строки...) означает, что вы идете не в направлении расширения стека, а в направлении происхождения стека, в конечном счете перебирая его и погружаясь к своей смерти на практически не отображенной защитной странице, и в этом случае вы получаете хорошее сообщение об ошибке, которое вы упомянули,

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

Кроме того: изменение чего-либо вообще может изменить поведение вашего кода, поскольку платформа не обязана вести себя таким образом.
2-й в стороне: поразительная вещь в том, что strcpy(c, b); ведет себя так, как будто он не перезаписывает терминатор строки, начинающейся в b и заканчивается в c,

Я получаю вывод, как это, используя компилятор gcc:

a = abcdefghijklmnop
b = 
c = 

a = abcdefghijklmnopABCDEFGHIJKLMNOP
b = ABCDEFGHIJKLMNOP
c = 

a = abcdefghijklmnopABCDEFGHIJKLMNOP
b = ABCDEFGHIJKLMNOP
c = ABCDEFGHIJKLMNOP

a = 
b = ABCDEFGHIJKLMNOP
c = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP

Это потому, что вы не предоставляете требуемый размер для терминатора. Просто попробуйте:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char a[17];
    char b[17];
    char c[33];

    strcpy(a, "abcdefghijklmnop");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(b, "ABCDEFGHIJKLMNOP");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcat(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    return 0;
}

Теперь все хорошо. Спасибо, Болдрик.

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