Что такое разрушение стека и как мне это исправить? - PullRequest
3 голосов
/ 19 сентября 2019

Цель этой программы - определить, является ли число от 1 до 1000 простым числом, путем проверки его делимости на первые 11 простых целых чисел.Программа работает правильно с большинством входов.Однако, когда я ввожу целое число, такое как 468, обнаруживается разрушение стека.Что такое разрушение стека и как мне решить эту проблему?

Я пытался исследовать разрушение стека, но не могу найти конкретных примеров, связанных с моей программой.Я не знаю альтернативных методов, я мог бы попытаться изменить программу, так как я относительно новичок в программировании на C.

char divStatement[] = " is divisible by ";

if ((userInput % 31) == 0) {
    div31 = true;
    strcat(divStatement, "31, ");
}

if (div2 || div3 || div5 || div7 || div11 || div13 || div17 || div19 || div23 || div29 || div31) {
        divStatement[strlen(divStatement) - 2] = '.';
        divStatement[strlen(divStatement) - 1] = '\n';
        printf("%d%s", userInput, divStatement);
        printf("%d is not prime.\n", userInput);
}
else {
        printf("%d is prime.\n", userInput);
}

Вывод на самом деле работает правильно.Однако в конце программы терминал выводит:

***stack smashing detected ***: ./a.out terminated 
Aborted

Ответы [ 4 ]

10 голосов
/ 19 сентября 2019
char divStatement[] = " is divisible by ";

if ((userInput % 31) == 0) {
    div31 = true;
    strcat(divStatement, "31, ");
}

divStatement - массив символов, достаточно большой, чтобы вместить " is divisible by " плюс терминатор \0.Вы не можете добавить "31, " к нему, потому что у него нет свободного места.

Простое решение - дать массиву явную длину, достаточную для обработки всего, что может добавить ваша программа.

char divStatement[1000] = " is divisible by ";
2 голосов
/ 20 сентября 2019

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

Вы не объявляете массив символов с определенным размером, а потому, что инициализируете его строковым литералом , размер массива символов divStatement установлен равным 18 байтам.(17 для символов в " is divisible by " и 1 для "\0", так называемый нулевой символ , используемый для завершения строки).Из стандарта C99 6.4.5 / 5 «Строковые литералы - семантика» (как указано в ответе на этот вопрос ):

Затем используется многобайтовая последовательность символов для инициализациимассив статической длительности и длины хранилища, достаточный только для того, чтобы содержать последовательностьне следует изменять данные после 18-го байта (по соображениям безопасности).Когда вы объединяете строки, вы фактически пытаетесь записать более 18 байтов, что вызывает механизм безопасности, который, в свою очередь, приводит к ошибке.

Поскольку вы проверяете только числа от 1 до 1000 и только с первыми 11 простыми числами, вы знаете, что простое число будет иметь длину не более 3 символов.Вместе с ", " это добавляет 5 дополнительных символов, следовательно, 18 + 5 = 23 символа в целом.Таким образом, ваша проблема легко решается путем явного объявления divStatement в виде массива символов размером 23, то есть divStatement[23] = " is divisible by ".Что касается получения более общего отзыва о вашем коде, вы должны проверить сообщество проверки кода .

1 голос
/ 20 сентября 2019

Определение Stack Smashing, опубликованное по адресу: https://www.techopedia.com/definition/16157/stack-smashing

Definition - Что означает Stack Smashing?

* Stack Smashing - это форма уязвимости, когда стек компьютераприложение или ОС вынуждены переполняться.Это может привести к подрыву программы / системы и ее поломке.

Стек, схема «первым пришел - последним вышел», является формой буфера, содержащего промежуточные результаты операций внутри него.Чтобы упростить, разбить стек, поместив в стек больше данных, чем его емкость.Опытные хакеры могут сознательно вводить избыточные данные в стек.Избыточные данные могут храниться в других переменных стека, включая адрес возврата функции.Когда функция возвращается, она переходит к вредоносному коду в стеке, который может повредить всю систему.Это влияет на смежные данные в стеке и вызывает сбой программы. *

относительно:

char divStatement[] = " is divisible by ";

и

strcat(divStatement, "31, ");

Вызов strcat()пытаясь добавить строку: «31» к массиву, который является достаточно большим, чтобы содержать строку: «делится на».В результате массив переполняется.Такое переполнение является неопределенным поведением.В этом случае он повредил стек, вероятно, прямо там, где расположен какой-либо кадр стека или другая связь

1 голос
/ 20 сентября 2019

Это не ответ на ваш вопрос, а частичный ответ на вопрос, который вы должны были задать.Я устал, чтобы придумать правильное объяснение.Но вам нужно что-то вроде этого где-то в вашем коде:

if ((userInput % n) == 0)
  {
    printf("%d is divisible by %d\n", userInput, n);
    is_prime == 0;
  }

Наличие массива всех 11 первых простых чисел, вероятно, также хорошая идея:

const int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};

Я не собираюсьиспортить все 7 забав, рассказав вам, как обернуть это в цикл, и как объявить / инициализировать n и is_prime.Веселитесь с домашней работой.Я надеюсь, что крайний срок не слишком скоро: -)

...