Подтвердить что ты не робот

Изучение С++: пример в С++

Что может быть простым примером в С++, который вызывает переполнение стека в случае вызова и возврата из вызовов метода. Я знаком с вызывающим соглашением, т.е. Thiscall, stdcall и cdecl, и способ очистки стека. В частности, не будет ли стекирование под потоком заботиться о коде, сгенерированном компилятором, автоматически для меня?

Какие ситуации могут вызвать проблемы со стеком?

4b9b3361

Ответ 1

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

В конкретном случае функций-членов вызовное соглашение обычно называется thiscall и зависит от компилятора от вызывающего или вызывающего пользователя.

Подробнее об условных вызовах см. здесь.

Ответ 2

Я не уверен, что вы говорите о стеке структуры данных и проблемах с потоком в нем или что-то еще. Что касается проблемы stack(data structure) underflow, здесь есть объяснение.

stack - это последний абстрактный тип данных и структура данных (LIFO). Стек может иметь любой абстрактный тип данных как элемент, но характеризуется только тремя основными операциями: push, поп и сверху > .

Операция push добавляет новый элемент в начало стека или инициализирует стек, если он пуст. Если стек заполнен и не содержит достаточного количества пространства для приема данного элемента, тогда считается, что стек находится в состоянии переполнения. Поп-операция удаляет элемент из верхней части стека.

A pop отображает ранее скрытые элементы или приводит к пусту стеку, но если стек пуст, он переходит в состояние underflow (это означает, что нет элементов присутствовать в стеке, которое нужно удалить).

Операция top top получает данные из самой верхней позиции и возвращает ее пользователю без ее удаления. То же самое состояние переполнения может также возникать в операции верхнего стека, если стек пуст.

Рассмотрим пример реализации стека:

template <class Item> class Stack 
{
public:
    bool isEmpty() const;
    size_t size() const;
    Item pop();
    void push(const Item& it);
private:

};

Теперь рассмотрим следующие операции, выполняемые в этом стеке.

C++ command                      resulting stack
------------------------------------------------
Stack<int> S;
                                  _____ (empty stack of ints)



S.push(7);                            
                                  | 7 |  <-- top
                                  -----

S.push(2);                            
                                  | 2 |  <-- top 
                                  | 7 |
                                  -----

S.push(73);                           
                                  |73 |  <-- top 
                                  | 2 |
                                  | 7 |
                                  -----

S.pop();                           
                                  | 2 |  <-- top
                                  | 7 |                    -----
S.pop();      
                                  -----
S.pop();                           
                                  | 7 |  <-- top
                                  -----
S.pop();                           
                                  -----  (empty)

S.pop();                           
                    ERROR "stack underflow"

Ответ 3

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

Ответ 4

Если вы когда-либо находитесь в ситуации, когда может произойти переполнение стека вызовов, скорее всего, ваша программа умрет от насильственной смерти до того, как это произойдет. По крайней мере, если я понимаю, как работает функция вызова функций.

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

В любом случае важно то, что после вызова функции стек равен одному или нескольким байтам короче, чем предполагается. Теоретически программа будет продолжена, выбирая нужный объем данных, но оставаясь на одном или нескольких байтах меньше ожидаемого. В конце концов, больше нет данных, чтобы выскочить, и у вас есть недостаточное количество стеков.

Однако, ссылаясь на стек, адреса относятся к вершине. Таким образом, компилятор будет искать определенный объект в [top of stack + 3], если он находится в трех байтах от вершины стека. Он все равно сделает это, если стек окажется короче, чем ожидалось, и найдите этот объект в неправильном месте. Предполагая, что объект все еще там... он, возможно, случайно уже исчез. Когда вы дойдете до конца любой функции, в которой вы находитесь, она может оказаться неспособной найти правильный адрес возврата по этой же причине, но даже если это произойдет, все поврежденные вами объекты будут довольно тяжелой ситуацией в.

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