Среди многочисленных проблем программного характера, возникающих при работе с компьютером, пользователям может встречаться ошибка, сообщающая об обнаружении переполнения стекового буфера в конкретном приложении и возможности получения злоумышленником управления данными софта. Этому багу уже десятки лет, но и сегодня разрабатываемые программы не могут похвастать абсолютной надёжностью. Переполнение стековой памяти может возникать у любого неидеально продуманного приложения, что влечёт за собой аварийное закрытие или зависание софта, а также позволяет злоумышленнику внедрить вредоносный код, выполняемый от имени уязвимой программы. Если при этом приложение выполняется с наивысшими привилегиями, это открывает путь взломщику к любым манипуляциям в системе.
Бывает, что переполнение буфера при программировании продукта является средством, служащим определённым целям, например, намеренно применяется системным софтом для обхода отдельных ограничений. Рассмотрим подробнее, что это за явление, почему возникает и как избавиться от системной ошибки.
Причины возникновения ошибки переполнения стекового буфера
Для размещения данных программами используются блоки памяти (буферы), обычно фиксированной длины, то есть вмещающие ограниченный объём информации. Ошибка переполнения стекового буфера возникает, когда приложение пишет больше данных, чем выделено под стековый буфер, провоцируя перезаписывание, и не исключено, что будут перезаписаны важные избыточные данные в стеке, расположенные следом за массивом или перед ним.
Стек (абстрактный тип данных) являет собой список элементов, располагающихся стопкой, где информация упорядочена таким образом, что добавление элемента делает его головным, а удаление убирает первый элемент, тогда как головным станет следующий за ним. Принцип работы стека часто сравнивается со стопкой тарелок – выдернуть из середины тарелку нельзя, снимаются они поочерёдно, начиная с верхней, то есть порядок взаимодействия осуществляется по принципу LIFO (Last In, First Out – последним пришёл, первым ушёл).
Такое явление как переполнение буфера, когда программа захватывает больше данных, чем выделенный под них массив, в лучшем случае при ошибочном переполнении приводит к отказу софта или некорректной работе. В худшем, это будет означать, что уязвимость может быть применена в целях вредительства. Переполнение в стековом кадре используется злоумышленниками для изменения адреса возврата выполняемой функции, открывая возможности управления данными, независимо от того, буфер расположен в стеке, который растёт вниз, и адрес возврата идёт после буфера, или же стек растёт вниз, и адрес возврата находится перед буфером. Реализовать такое поведение программы несложно с применением вредоносного кода. С блоками памяти определённого размера компьютер работает в любых приложениях или процессах.
Так, в своих целях применять переполнение стекового буфера могут сетевые черви или иной вредоносный софт. Особенно опасными являются эксплойты, использующие уязвимость, которые предназначаются для получения привилегий путём передачи программе намеренно созданных входных данных, повреждающих стек. Эти данные переполняют буфер и меняют данные, следующие в памяти за массивом.
Скачивание сомнительного, взломанного программного обеспечения, включая пиратские сборки Виндовс, всегда таит в себе определённые риски, поскольку содержимое может хранить вредоносный код, выполняющийся при установке софта на компьютер.
Что делать, если обнаружена уязвимость в данном приложении
Первое, что нужно сделать в том случае, когда ошибка проявилась в конкретной программе, это попробовать её переустановить, загрузив инсталлятор из проверенного источника, лучше официального. Перед инсталляцией софта следует убедиться в его безопасности, просканировав антивирусом, особенно внимательно нужно устанавливать ПО при пакетной установке, когда в довесок к скачиваемому продукту идут и дополнительные элементы, часто вредоносные или просто ненужные. Переустановка софта и перезагрузка компьютера избавляют от ошибки, если она была случайной.
Рассмотрим, несколько способов, как исправить ошибку, если произошло переполнение стекового буфера Windows 10.
Использование антивирусного ПО
В тексте ошибки переполнения буфера говорится о потенциальной угрозе безопасности, и, несмотря на достаточно преклонный возраст и известность бага, он всё ещё актуален и нередко становится средством взлома систем. Причём сбою поддаются программы различных типов, а спровоцировать его можно специально задействованным вредоносным софтом.
Рекомендуется просканировать систему на вирусы, можно в безопасном режиме, если ОС не загружается, и выполнить проверку и устранение угроз посредством встроенного Защитника Windows.
Как очистить компьютер от вирусов при появлении ошибки «Стековый буфер переполнен»:
- Открываем Защитник Windows через поисковую строку меню «Пуск» или в области уведомлений на панели задач;
- Выбираем «Защита от вирусов и угроз» и переходим к параметрам сканирования;
- Отмечаем флажком «Автономное сканирование Защитника Windows» и жмём соответствующую кнопку для начала проверки.
Чистая загрузка ОС Windows
Если переустановка софта и перезагрузка не помогли, и ошибка переполнения стекового буфера не исчезла, стоит попробовать выполнить чистую загрузку системы. Возможно, причины проблемы не относятся к данному приложению, ведь кроме работающих программ в Windows запущен ряд прочих процессов, которые и могут провоцировать баг. Для выполнения загрузки ОС в чистом виде нужно войти под учётной записью администратора компьютера, некоторые функции и приложения при этом будут недоступны, поскольку в данном режиме запускаются только необходимые системе файлы.
Для чистой загрузки Windows выполняем следующие действия:
- Открываем консоль «Выполнить» (Win+R), вводим в поле команду msconfig, жмём «Ок» или клавишу Enter.
- В окне «Конфигурация системы» на вкладке «Общие» снимаем отметку с пункта «Загружать элементы автозагрузки». Затем на вкладке «Службы» отмечаем пункт «Не отображать службы Майкрософт» и жмём кнопку «Отключить все».
- Идём на вкладку «Автозагрузка» и жмём ссылку «Открыть диспетчер задач» (для Windows 10), в открывшемся окне Диспетчера задач поочерёдно отключаем каждую программу в списке.
- Возвращаемся к окну конфигурации и жмём «Ок», после чего перезагружаемся и проверяем, исчезла ли ошибка.
Для того чтобы выявить программу, ставшую причиной проблемы, нужно включать софт по одному в автозагрузке и службах, после чего выполнять перезагрузку.
Специализированный софт
В сети есть немало лечащих утилит (Dr.Web CureIt, Kaspersky и др.), способных избавить компьютер от вирусов. Портативные программы не будут конфликтовать с уже установленным антивирусом и эффективно выполнят задачу сканирования и удаления вредоносного ПО. Есть также антивирусный софт, способный решать проблему на низком уровне, если вирусы не дают системе запуститься. Используя утилиты с обновлённой вирусной базой, можно исправить, в том числе ошибку переполнения стекового буфера.
Восстановление Windows
Ещё одна мера, позволяющая избавится от системной ошибки, предполагает выполнение восстановления системы. Для использования функции потребуется наличие заранее созданного накопителя восстановления Windows, в качестве которого можно использовать диск или флешку. Выполняем следующие действия:
- отключаем от компьютера лишние устройства, не требуемые для работы;
- вставляем загрузочный накопитель и загружаемся с него, предварительно выставив приоритет загрузки в BIOS;
- выбираем «Восстановление системы» – «Диагностика» – «Дополнительные параметры» – «Восстановление при загрузке», далее выбираем ОС, которую требуется восстановить, и ждём окончания процесса, перезагружаемся.
Крайней мерой, когда более простые и гуманные способы решения не помогли исправить ошибку, является переустановка Windows.
Stack
A stack, in this context, is the last in, first out buffer you place data while your program runs. Last in, first out (LIFO) means that the last thing you put in is always the first thing you get back out — if you push 2 items on the stack, ‘A’ and then ‘B’, then the first thing you pop off the stack will be ‘B’, and the next thing is ‘A’.
When you call a function in your code, the next instruction after the function call is stored on the stack, and any storage space that might be overwritten by the function call. The function you call might use up more stack for its own local variables. When it’s done, it frees up the local variable stack space it used, then returns to the previous function.
Stack overflow
A stack overflow is when you’ve used up more memory for the stack than your program was supposed to use. In embedded systems you might only have 256 bytes for the stack, and if each function takes up 32 bytes then you can only have function calls 8 deep — function 1 calls function 2 who calls function 3 who calls function 4 …. who calls function 8 who calls function 9, but function 9 overwrites memory outside the stack. This might overwrite memory, code, etc.
Many programmers make this mistake by calling function A that then calls function B, that then calls function C, that then calls function A. It might work most of the time, but just once the wrong input will cause it to go in that circle forever until the computer recognizes that the stack is overblown.
Recursive functions are also a cause for this, but if you’re writing recursively (ie, your function calls itself) then you need to be aware of this and use static/global variables to prevent infinite recursion.
Generally, the OS and the programming language you’re using manage the stack, and it’s out of your hands. You should look at your call graph (a tree structure that shows from your main what each function calls) to see how deep your function calls go, and to detect cycles and recursion that are not intended. Intentional cycles and recursion need to be artificially checked to error out if they call each other too many times.
Beyond good programming practices, static and dynamic testing, there’s not much you can do on these high level systems.
Embedded systems
In the embedded world, especially in high reliability code (automotive, aircraft, space) you do extensive code reviews and checking, but you also do the following:
- Disallow recursion and cycles — enforced by policy and testing
- Keep code and stack far apart (code in flash, stack in RAM, and never the twain shall meet)
- Place guard bands around the stack — empty area of memory that you fill with a magic number (usually a software interrupt instruction, but there are many options here), and hundreds or thousands of times a second you look at the guard bands to make sure they haven’t been overwritten.
- Use memory protection (ie, no execute on the stack, no read or write just outside the stack)
- Interrupts don’t call secondary functions — they set flags, copy data, and let the application take care of processing it (otherwise you might get 8 deep in your function call tree, have an interrupt, and then go out another few functions inside the interrupt, causing the blowout). You have several call trees — one for the main processes, and one for each interrupt. If your interrupts can interrupt each other… well, there be dragons…
High-level languages and systems
But in high level languages run on operating systems:
- Reduce your local variable storage (local variables are stored on the stack — although compilers are pretty smart about this and will sometimes put big locals on the heap if your call tree is shallow)
- Avoid or strictly limit recursion
- Don’t break your programs up too far into smaller and smaller functions — even without counting local variables each function call consumes as much as 64 bytes on the stack (32 bit processor, saving half the CPU registers, flags, etc)
- Keep your call tree shallow (similar to the above statement)
Web servers
It depends on the ‘sandbox’ you have whether you can control or even see the stack. Chances are good you can treat web servers as you would any other high level language and operating system — it’s largely out of your hands, but check the language and server stack you’re using. It is possible to blow the stack on your SQL server, for instance.
-Adam
Stack
A stack, in this context, is the last in, first out buffer you place data while your program runs. Last in, first out (LIFO) means that the last thing you put in is always the first thing you get back out — if you push 2 items on the stack, ‘A’ and then ‘B’, then the first thing you pop off the stack will be ‘B’, and the next thing is ‘A’.
When you call a function in your code, the next instruction after the function call is stored on the stack, and any storage space that might be overwritten by the function call. The function you call might use up more stack for its own local variables. When it’s done, it frees up the local variable stack space it used, then returns to the previous function.
Stack overflow
A stack overflow is when you’ve used up more memory for the stack than your program was supposed to use. In embedded systems you might only have 256 bytes for the stack, and if each function takes up 32 bytes then you can only have function calls 8 deep — function 1 calls function 2 who calls function 3 who calls function 4 …. who calls function 8 who calls function 9, but function 9 overwrites memory outside the stack. This might overwrite memory, code, etc.
Many programmers make this mistake by calling function A that then calls function B, that then calls function C, that then calls function A. It might work most of the time, but just once the wrong input will cause it to go in that circle forever until the computer recognizes that the stack is overblown.
Recursive functions are also a cause for this, but if you’re writing recursively (ie, your function calls itself) then you need to be aware of this and use static/global variables to prevent infinite recursion.
Generally, the OS and the programming language you’re using manage the stack, and it’s out of your hands. You should look at your call graph (a tree structure that shows from your main what each function calls) to see how deep your function calls go, and to detect cycles and recursion that are not intended. Intentional cycles and recursion need to be artificially checked to error out if they call each other too many times.
Beyond good programming practices, static and dynamic testing, there’s not much you can do on these high level systems.
Embedded systems
In the embedded world, especially in high reliability code (automotive, aircraft, space) you do extensive code reviews and checking, but you also do the following:
- Disallow recursion and cycles — enforced by policy and testing
- Keep code and stack far apart (code in flash, stack in RAM, and never the twain shall meet)
- Place guard bands around the stack — empty area of memory that you fill with a magic number (usually a software interrupt instruction, but there are many options here), and hundreds or thousands of times a second you look at the guard bands to make sure they haven’t been overwritten.
- Use memory protection (ie, no execute on the stack, no read or write just outside the stack)
- Interrupts don’t call secondary functions — they set flags, copy data, and let the application take care of processing it (otherwise you might get 8 deep in your function call tree, have an interrupt, and then go out another few functions inside the interrupt, causing the blowout). You have several call trees — one for the main processes, and one for each interrupt. If your interrupts can interrupt each other… well, there be dragons…
High-level languages and systems
But in high level languages run on operating systems:
- Reduce your local variable storage (local variables are stored on the stack — although compilers are pretty smart about this and will sometimes put big locals on the heap if your call tree is shallow)
- Avoid or strictly limit recursion
- Don’t break your programs up too far into smaller and smaller functions — even without counting local variables each function call consumes as much as 64 bytes on the stack (32 bit processor, saving half the CPU registers, flags, etc)
- Keep your call tree shallow (similar to the above statement)
Web servers
It depends on the ‘sandbox’ you have whether you can control or even see the stack. Chances are good you can treat web servers as you would any other high level language and operating system — it’s largely out of your hands, but check the language and server stack you’re using. It is possible to blow the stack on your SQL server, for instance.
-Adam
Ошибки с указанием на переполнение стекового обмена в Windows всегда являются поводом для беспокойства, поскольку могут они служить признаком деятельности вредоносной программы, по крайней мере, так указывается в описании ошибки. В действительности ошибка «Обнаружено переполнение стекового буфера в данном приложении» при запуске программы может иметь и другие причины, например, наличие в коде приложения багов.
Причем необязательно, чтобы баг находился именно в том приложении, имя которого указывается в заголовке ошибки.
Что такое ошибка переполнения стекового буфера
Данная ошибка возникает, когда определенная программа записывает в буфер определенного стека объем данных, превышающий «лимит» памяти этого стека. По сути, сбой вызывается нехваткой памяти. Как уже было сказано, переполнение буфера стека может быть вызвано скрытой работой вредоносного ПО, некорректной работой драйверов, антивирусов и других программ, работающих в режиме ядра. Отмечены случаи появления неполадки в процессе работы программного обеспечения для майнинга криптовалют.
Что делать при возникновении ошибки переполнения буфера стека
Если ошибка возникла в стороннем приложении, лучшим решением станет переустановка программы. В первую очередь это касается репаков, в коде которых нередко встречаются баги. Если ошибка указывает на файл драйвера устройства, доступного в оснастке «Диспетчер устройства», ищем этот драйвер и переустанавливаем, обновляем или откатываем его.
В случае возникновения ошибки при работе или запуске системных приложений и служб, выполняем откат Windows к ближайшей точке восстановления.
Также можно попробовать выполнить сканирования системы на предмет поврежденных файлов командой sfc /scannow, выполненной в запущенной с правами администратора командной строке или консоли PowerShell.
Если команда sfc возвращает ошибку, восстанавливаем хранилище компонентов командой:
Dism /Online /Cleanup-Image /RestoreHealth
Еще одним вариантом является тест системы в режиме чистой загрузки.
Откройте командой msconfig утилиту «Конфигурация системы», перейдите на вкладку «Службы», установите флажок в пункте «Не отображать службы Microsoft», после чего отключите все оставшиеся в списке службы и перезагрузите компьютер.
Если ошибка не появится, значит источником является одна из отключенных сторонних служб.
Напоминаем, что определить ее можно методом исключения.
Загрузка…
Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded
Это когда вызывается слишком много вложенных функций
Это когда вызывается слишком много вложенных функций
Ситуация: заказчик попросил разместить на странице кликабельную картинку, а чтобы на неё обратило внимание больше посетителей, попросил сделать вокруг неё моргающую рамку. Логика моргания в скрипте очень простая:
- В первой функции находим на странице нужный элемент.
- Добавляем рамку с какой-то задержкой (чтобы она какое-то время была на экране).
- Вызываем функцию убирания рамки.
- Внутри второй функции находим тот же элемент на странице.
- Убираем рамку с задержкой.
- Вызываем первую функцию добавления рамки.
Код простой, поэтому делаем всё в одном файле:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pulse</title>
<style type="text/css">
/* рамка, которая будет моргать */
.pulse { box-shadow: 0px 0px 4px 4px #AEA79F; }
</style>
</head>
<body>
<div id="pulseDiv">
<a href="#">
<div id="advisersDiv">
<img src="https://thecode.media/wp-content/uploads/2020/08/photo_2020-08-05-12.04.57.jpeg">
</div>
</a>
</div>
<!-- подключаем jQuery -->
<script src="https://yastatic.net/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
<!-- наш скрипт -->
<script type="text/javascript">
// добавляем рамку
function fadeIn() {
// находим нужный элемент и добавляем рамку с задержкой
$('#pulseDiv').find('div#advisersDiv').delay(400).addClass("pulse");
// затем убираем рамку
fadeOut();
};
// убираем рамку
function fadeOut() {
// находим нужный элемент и убираем рамку с задержкой
$('#pulseDiv').find('div#advisersDiv').delay(400).removeClass("pulse");
// затем добавляем
fadeIn();
};
// запускаем моргание рамки
fadeIn();
</script>
</body>
</html>
Но при открытии страницы в браузере мы видим, что ничего не моргает, а в консоли появилась ошибка:
❌ Uncaught RangeError: Maximum call stack size exceeded
Что это значит: в браузере произошло переполнение стека вызовов и из-за этого он не может больше выполнять этот скрипт.
Переполнения стека простыми словами означает вот что:
- Когда компьютер что-то делает, он это делает последовательно —
1
,2
,3
,4
. - Иногда ему нужно отвлечься от одного и сходить сделать что-то другое — а, б, в, г, д. Получается что-то вроде
1
,2
,3 → а
,б
,в
,г
,д → 4
. - Вот эти переходы
3 → а
ид → 4
— это компьютеру нужно запомнить, что он выполнял пункт 3, и потом к нему вернуться. - Каждое запоминание, что компьютер бросил и куда ему нужно вернуться, — это называется «вызов».
- Вызовы хранятся в стеке вызовов. Это стопка таких ссылок типа «когда закончишь вот это, вернись туда».
- Стек не резиновый и может переполняться.
Что делать с ошибкой Uncaught RangeError: Maximum call stack size exceeded
Эта ошибка — классическая ошибка переполнения стека во время выполнения рекурсивных функций.
Рекурсия — это когда мы вызываем функцию внутри самой себя, но чуть с другими параметрами. Когда параметр дойдёт до конечного значения, цепочка разматывается обратно и функция собирает вместе все значения. Это удобно, когда у нас есть чёткий алгоритм подсчёта с понятными правилами вычислений.
В нашем случае рекурсия возникает, когда в конце обеих функций мы вызываем другую:
- Функции начинают бесконтрольно вызывать себя бесконечное число раз.
- Стек вызовов начинает запоминать вызов каждой функции, чтобы, когда она закончится, вернуться к тому, что было раньше.
- Стек — это определённая область памяти, у которой есть свой объём.
- Вызовы не заканчиваются, и стек переполняется — в него больше нельзя записать вызов новой функции, чтобы потом вернуться обратно.
- Браузер видит всё это безобразие и останавливает скрипт.
То же самое будет, если мы попробуем запустить простую рекурсию слишком много раз:
Как исправить ошибку Uncaught RangeError: Maximum call stack size exceeded
Самый простой способ исправить эту ошибку — контролировать количество рекурсивных вызовов, например проверять это значение на входе. Если это невозможно, то стоит подумать, как можно переделать алгоритм, чтобы обойтись без рекурсии.
В нашем случае проблема возникает из-за того, что мы вызывали вторые функции бесконтрольно, поэтому они множились без ограничений. Решение — ограничить вызов функции одной секундой — так они будут убираться из стека и переполнения не произойдёт:
<script type="text/javascript">
// добавляем рамку
function fadeIn() {
// находим нужный элемент и добавляем рамку с задержкой
$('#pulseDiv').find('div#advisersDiv').delay(400).addClass("pulse");
// через секунду убираем рамку
setTimeout(fadeOut,1000)
};
// убираем рамку
function fadeOut() {
// находим нужный элемент и убираем рамку с задержкой
$('#pulseDiv').find('div#advisersDiv').delay(400).removeClass("pulse");
// через секунду добавляем рамку
setTimeout(fadeIn,1000)
};
// запускаем моргание рамки
fadeIn();
</script>
Вёрстка:
Кирилл Климентьев
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Переполнение стека
- Определение
- Стек программы
- Последствия ошибки
- Причины ошибки
- Примеры
- Итог
- Библиографический список
Определение
Переполнение стека — программная ошибка времени выполнения, при которой программа захватывает всю память, выделенную ей под стек, что обычно приводит к аварийному завершению её работы.
Стек программы
Стек программы — это специальная области памяти, организованная по принципу очереди LIFO (Last in, first out — последним пришел, первым ушел). Название «стек» произошло из-за аналогии принципа его построения со стопкой (англ. stack) тарелок — можно класть тарелки друг на друга (метод добавления в стек, «заталкивание», «push»), а затем забирать их, начиная с верхней (метод получения значения из стека, «выталкивание», «pop»). Стек программы также называют стек вызовов, стек выполнения, машинным стеком (чтобы не путать его со «стеком» — абстрактной структурой данных).
Для чего нужен стек? Он позволяет удобно организовать вызов подпрограмм. При вызове функция получает некоторые аргументы; также она должна где-то хранить свои локальные переменные. Кроме того, надо учесть, что одна функция может вызвать другую функцию, которой тоже надо передавать параметры и хранить свои переменные. Используя стек, при передаче параметров нужно просто положить их в стек, тогда вызываемая функция сможет их оттуда «вытолкнуть» и использовать. Локальные переменные тоже можно хранить там же — в начале своего кода функция выделяет часть памяти стека, при возврате управления — очищает и освобождает. Программисты на высокоуровневых языках обычно не задумываются о таких вещах — весь необходимый рутинный код за них генерирует компилятор.
Последствия ошибки
Теперь мы подошли почти вплотную к проблеме. В абстрактном виде стек представляет собой бесконечное хранилище, в которое можно бесконечно добавлять новые элементы. К сожалению, в нашем мире все конечно — и память под стек не исключение. Что будет, если она закончится, когда в стек заталкиваются аргументы функции? Или функция выделяет память под свои переменные?
Произойдет ошибка, называемая переполнением стека. Поскольку стек необходим для организации вызова пользовательских функций (а практически все программы на современных языках, в том числе объектно-ориентированных, так или иначе строятся на основе функций), больше они вызываться не смогут. Поэтому операционная система забирает управление, очищает стек и завершает программу. Здесь можно подчеркнуть различие между переполнением буфера и переполнением стека — в первом случае ошибка происходит при обращении к неверной области памяти, и если защита на этом этапе отсутствует, в этот момент не проявляет себя — при удачном стечении обстоятельств программа может отработать нормально. Если только память, к которой шло обращение, была защищена, происходит ошибка сегментации. В случае со стеком программа непременно завершается.
Чтобы быть совсем точным, следует отметить, что подобное описание событий верно лишь для компиляторов, компилирующих в «родной» (native) код. В управляемых языках у виртуальной машины есть свой стек для управляемых программ, за состоянием которого гораздо проще следить, и можно даже позволить себе при возникновении переполнения передать программе исключение. В языках Си и Си++ на подобную «роскошь» рассчитывать не приходится.
Причины ошибки
Что же может привести к такой неприятной ситуации? Исходя из описанного выше механизма, один из вариантов — слишком большое число вложенных вызовов функций. Особенно вероятен такой вариант развития событий при использовании рекурсии. Бесконечная рекурсия (при отсутствии механизма «ленивых» вычислений) прерывается именно таким образом, в отличие от бесконечного цикла, который иногда имеет полезное применение. Впрочем, при небольшом объеме памяти, отведенной под стек (что, например, характерно для микроконтроллеров), достаточно может быть и простой последовательности вызовов.
Другой вариант — локальные переменные, требующие большого количества памяти. Заводить локальный массив из миллиона элементов, или миллион локальных переменных (мало ли что бывает) — не самая лучшая идея. Даже один вызов такой «жадной» функции легко может вызвать переполнение стека. Для получения больших объемов данных лучше воспользоваться механизмами динамической памяти, которая позволит обработать ошибку её нехватки.
Однако динамическая память является довольно медленной в плане выделения и освобождения (поскольку этим занимается операционная система), кроме того, при прямом доступе приходится вручную выделять её и освобождать. Память же в стеке выделяется очень быстро (по сути, надо лишь изменить значение одного регистра), кроме того, у объектов, выделенных в стеке, автоматически вызываются деструкторы при возврате управления функцией и очистке стека. Разумеется, тут же возникает желание получить память из стека. Поэтому третий путь к переполнению — самостоятельное выделение в стеке памяти программистом. Специально для этой цели библиотека языка Си предоставляет функцию alloca. Интересно заметить, что если у функции для выделения динамической памяти malloc есть свой «близнец» для её освобождения free, то у функции alloca его нет — память освобождается автоматически после возврата управления функцией. Возможно, это только осложняет ситуацию — ведь до выхода из функции освободить память не получится. Даже несмотря на то, что согласно man-странице «функция alloca зависит от машины и компилятора; во многих системах ее реализация проблематична и содержит много ошибок; ее использование очень несерьезно и не одобряется» — она все равно используется.
Примеры
В качестве примера рассмотрим код для рекурсивного поиска файлов, расположенный на MSDN:
void DirSearch(String* sDir)
{
try
{
// Find the subfolders in the folder that is passed in.
String* d[] = Directory::GetDirectories(sDir);
int numDirs = d->get_Length();
for (int i=0; i < numDirs; i++)
{
// Find all the files in the subfolder.
String* f[] = Directory::GetFiles(d[i],textBox1->Text);
int numFiles = f->get_Length();
for (int j=0; j < numFiles; j++)
{
listBox1->Items->Add(f[j]);
}
DirSearch(d[i]);
}
}
catch (System::Exception* e)
{
MessageBox::Show(e->Message);
}
}
Эта функция получает список файлов указанной директории, а затем вызывает себя же для тех элементов списка, которые оказались директориями. Соответственно, при достаточно глубоком дереве файловой системы, мы получим закономерный результат.
Пример второго подхода, взятый из вопроса «Почему происходит переполнение стека?» с сайта под названием Stack Overflow (сайт является сборником вопросов и ответов на любые программистские темы, а не только по переполнению стека, как может показаться):
#define W 1000
#define H 1000
#define MAX 100000
//...
int main()
{
int image[W*H];
float dtr[W*H];
initImg(image,dtr);
return 0;
}
Как видно, в функции main выделяется память в стеке под массивы типов int и float по миллиону элементов каждый, что в сумме дает чуть менее 8 мегабайт. Если учесть, что по умолчанию Visual C++ резервирует под стек лишь 1 мегабайт, то ответ становится очевидным.
А вот пример, взятый из GitHub-репозитория проекта Flash-плеера Lightspark:
DefineSoundTag::DefineSoundTag(/* ... */)
{
// ...
unsigned int soundDataLength = h.getLength()-7;
unsigned char *tmp = (unsigned char *)alloca(soundDataLength);
// ...
}
Можно надеятся, что h.getLength()-7 не будет слишком большим числом, чтобы на следующей строчке не произошло переполнения. Но стоит ли сэкономленное на выделении памяти время «потенциального» вылета программы?
Итог
Переполнение стека — фатальная ошибка, которой наиболее часто страдают программы, содержащие рекурсивные функции. Однако даже если программа не содержит таких функций, переполнение все равно возможно из-за большого объема локальных переменных или ошибки в ручном выделении памяти в стеке. Все классические правила остаются в силе: если есть возможность выбора, вместо рекурсии лучше предпочесть итерацию, а также не заниматься ручной работой вместо компилятора.
Библиографический список
- Э. Таненбаум. Архитектура компьютера.
- Wikipedia. Stack Overflow.
- man 3 alloca.
- MSDN. How to recursively search folders by using Visual C++.
- Stack Overflow. Stack Overflow C++.
- GitHub. Lightspark — «tags.cpp».
Присылаем лучшие статьи раз в месяц
Владельцы компьютеров используют свои устройства для взаимодействия с различными программами. Однако при запуске некоторых приложений выскакивает окно с информацией о том, что произошло переполнение буфера стека операционной системы Windows 10 и неясно, как исправить ошибку. Также проблема сопровождается сообщением об опасности переполнения раздела, поэтому вам нужно как можно скорее найти способ решить проблему.
Из-за появившегося уведомления программа перестает работать. Аналогичная проблема возникает как в простых приложениях, так и в ресурсоемких играх. В обеих ситуациях проблема вызвана тем, что программа использует больше данных, чем может вместить буфер. Как правило, это происходит при майнинге криптовалюты, но и обычные пользователи сталкиваются с такими ошибками.
Избыточный буфер стека активно эксплуатируется злоумышленниками, которые используют установленное приложение для доступа к информации на компьютере. Поэтому владелец ПК может даже не подозревать, что на устройстве запущено вредоносное ПО, но оказывается, что процесс компрометации уже начался.
Что делать при обнаружении ошибки
Опасность, которую представляет ошибка, заставляет владельца компьютера немедленно искать пути решения проблемы. Однако не стоит действовать случайным образом, полагаясь на случайные рекомендации в Интернете. Необходимо выполнять действия в строгом соответствии с требованиями инструкции. Это сэкономит время и минимизирует риск дальнейших ошибок.
Совет. Попробуйте сначала переустановить программу. Не исключено, что после перезагрузки проблема исчезнет.
Переименовать BannerStore
Очевидно, что для решения проблемы нужно как-то очистить буфер стека. Проще всего это сделать через редактор реестра. Чтобы получить доступ к интерфейсу, относящемуся к следующей очистке буфера, обратитесь к справочным инструкциям:
- Нажмите Win + R на клавиатуре, чтобы открыть окно «Выполнить».
- Введите «regedit», чтобы запустить редактор реестра.
- Перейдите в каталог, расположенный по пути: «HKEY_CURRENT_USER Software Microsoft Windows CurrentVersion Explorer BannerStore».
- Щелкните правой кнопкой мыши каталог BannerStore».
- Щелкните «Переименовать».
- Придумайте другое имя для папки, состоящее из букв латинского алфавита.
Вам нужно будет перезагрузить компьютер, чтобы сохранить изменения. После повторного включения попробуйте снова открыть «проблемное» приложение, чтобы увидеть, решена ли проблема.
Проверка системных файлов SFC и DISM
Другой источник проблемы – сбой в работе системных файлов. Это негативно сказывается на всех приложениях сразу, но ошибка может появиться только в одной программе. Решение – проверить системные файлы и автоматически исправить проблемы.
Для этого вам нужно обратиться к справке командной строки. Интерфейс запускается через меню «Пуск», а также путем запроса «cmd» из окна «Выполнить».
После открытия нужного инструмента остается поочерёдно ввести следующие команды:
- sfc / scannow;
- DISM / Онлайн / Чистый образ / RestoreHealth;
- DISM / онлайн / Cleanup-Image / ScanHealth.
После ввода каждого запроса необходимо нажимать клавишу «Enter». В противном случае команды не распознаются системой. После завершения проверки остается перезагрузить ПК и снова попробовать запустить приложение.
Применение антивирусов
Поскольку очень часто вредоносное ПО является виновником ошибки, его необходимо устранить. Специальные антивирусы, такие как Kaspersky Internet Security, Avast и Dr. Spider Web. Кроме того, в операционной системе Windows 10 есть собственный защитник, который также выполняет аналогичную операцию:
- Из меню «Пуск» запустите «Настройки».
- Перейдите в раздел Обновление и безопасность».
- Выберите Защитник Windows».
- Нажмите кнопку «Открыть Защитник Windows».
- Запустите тест, нажав кнопку «Проверить сейчас».
В примечании. Защитник Windows позволяет выбрать уровень проверки (быстрый или полный). В этом случае пользователя должен заинтересовать второй вариант, который займет больше времени, однако с большой долей вероятности найдет и удалит вредоносные файлы.
Независимо от того, какой антивирус вы выбрали, запускается проверка вашего компьютера. Продолжительность операции определяется занятостью жесткого диска. Чем больше файлов хранит владелец ПК, тем дольше нужно ждать завершения сканирования. В конце концов, антивирус предложит избавиться от «паразитов», нажав кнопку «Удалить». Тогда вам просто нужно перезагрузить компьютер.
Чистая загрузка операционной системы
Стопроцентное решение проблемы – это чистая загрузка Windows 10. Но операция имеет ряд ограничений, в том числе необходимость прекращения использования некоторых системных программ:
- Откройте «Диспетчер задач» из меню «Пуск».
- Отключите все процессы во вкладке «Автозагрузка».
- Запустить окно «Выполнить».
- Введите приглашение «msconfig».
- На вкладке «Общие» снимите флажок «Загружать элементы автозагрузки».
- На вкладке «Автозагрузка» отключите все программы, а также установите флажок «Не показывать службы Microsoft».
- Перезагрузите компьютер.
Теперь устройство запустится в «чистом» режиме, благодаря которому в 90% случаев можно устранить проблему отдельных программ. Обязательно проверьте, помог ли этот метод исправить ошибку загрузки.
Специализированные утилиты
Если встроенные системные инструменты не помогают, имеет смысл прибегнуть к помощи стороннего программного обеспечения. Например CCleaner. Утилита предназначена для очистки вашего компьютера от мусора, а также позволяет очищать стековый буфер отдельных приложений.
При использовании CCleaner первое, что нужно сделать, это проверить стандартный элемент управления. Только после этого следует выбирать своевременные методы решения проблемы.
Восстановление или переустановка ОС
Когда не помогают даже сторонние утилиты, приходится прибегать к кардинальным мерам. Так принято называть операции, в рамках которых происходит полный сброс или переустановка системы. В первом случае пользователь загружает операционную систему из «безошибочной» точки восстановления, а во втором полностью удаляет содержимое жесткого диска.
Для восстановления вам потребуются:
- Зайдите в «Панель управления» через меню «Пуск».
- Откройте последовательно «Система и безопасность», «Система» и «Защита системы».
- Нажимаем кнопку «Сброс».
- Выберите точку восстановления и подтвердите операцию
Если откат не помог, сбросьте все настройки Windows:
- Открыть варианты».
- Перейдите в раздел Обновление и безопасность».
- Щелкните вкладку «Восстановить».
- Нажмите кнопку «Пуск».
Важный. Чтобы не потерять пользовательские файлы, необходимо предварительно создать резервную копию.
После сброса компьютер загрузится в исходном состоянии. Вы можете восстановить резервную копию, благодаря которой все программы вернутся и их запуск не будет сопровождаться ошибкой.
Источник изображения: it-tehnik.ru
В Telegram ко мне обратился один пользователь с ошибкой переполненного стекового буфера в Windows 10. Долго мы решали проблему, а точнее виновника, и нашли. Дело в том, что он майнил криптовалюту сутками и буфер в определенном стеке переполнялся. Я не хотел делать инструкцию так как думал, что это единичный случай, да и криптовалюта не моя стихия, но оказалось нет. Через некоторые время я обнаружил эту ошибку у себя в Discord, и еще один пользователь был с проблемой Twitch. В чем же соль?
Когда конкретная программа записывает большой объем данных в буфер определенного стека, превышающий объем памяти, выделенный для этого стека, то буфер на основе стека переполняется из-за нехватки памяти и вызывает фатальную ошибку. Ошибка также может возникнуть из-за неправильной работы системных файлов, или программы, которая написана кривым кодом. По сути, переполнение буфера считается опасным, в особенности, если это делает какая-либо сторонняя непонятная программа, так как можно делегировать права, и внедрять свой вредоносной код. Если вы оказались в такой ситуации, то разберем ошибку в Windows 10, которая звучит:
Обнаружено переполнение стекового буфера в данном приложении. Это переполнение может позволить злоумышленнику получить управление над данными приложением.
Переполнение стекового буфера в Windows 10 — Что делать?
Вы должны понимать, что переполнение стекового буфера может быть вызвана какой-либо программой или системным процессом. Попробуйте переустановить программу и скачать её с официального сайта, если она загружена с торрента. Вторым действием, воспользуетесь антивирусом и просканируйте всю систему. Запустите защитник Windows 10 и выберите параметр сканирования в автономном режиме. Также, рекомендую воспользоваться антивирусным сканером как Zemana или DrWeb.
Нажмите сочетание кнопок Win+R и введите regedit, чтобы открыть редактор реестра. В реестре перейдите по пути:
HKEY_CURRENT_USERSoftwareMicrosoftWindows CurrentVersionExplorerBannerStore
- Нажмите правой кнопкой мыши по BannerStore и переименуйте его.
Перезагрузите ПК
2. Проверка системных файлов SFC и DISM
Запустите командную строку от имени администратора и введите три команды по очереди, дожидаясь окончание процесса после каждой.
sfc /scannow
DISM /Online /Cleanup-Image /RestoreHealth
DISM /online /Cleanup-Image /ScanHealth
Перезагрузите ПК.
3. Обновление Windows 10
Если у вас критическая ошибка переполнение буферного стека, и вы ничего толком на рабочем столе сделать не можете, так как она мешает своим появлением, и у вас старая версия системы, то можно попробовать обновить Windows 10 через средство Update Assistant.
4. Восстановление системы
Создайте установочную флешку с Windows 10 и начните установку системы. Когда дойдете до пункта установки, то нажмите снизу на «Восстановление системы«.
Вас перебросит в дополнительные параметры загрузки, где вы можете попробовать «Восстановление системы», «Восстановление при загрузке» или выбрать «Параметры загрузки», чтобы запустить безопасный режим.
Если вы каким-либо способом решили проблему с переполнением буферного стека в Windows 10, то сообщите в комментариях, как решили, и что вызвало, чтобы помочь остальным пользователям в данной проблеме.
Смотрите еще:
- Буфер обмена в Windows 10 — Как использовать и очистить историю
- Как проверить оперативную память на ошибки в Windows
- Как сбросить Windows 10 без использования меню «Параметры»
- Восстановление Windows 10 с флешки
- Как установить windows 10, 8.1, 7, хр с флешки или диска
[ Telegram | Поддержать ]