Wpis z mikrobloga

Mikrobki musze napisac funkcje void stack() ktora bedzie powodowala przepelnienie sie stosu i w momencie gdy do tego dojdzie, program bedzie przerywany, a na ekranie zostanie wypisany stosowny komunikat (wewnatrz programu, nie przez kompilator). Main() ma wypisywac ile razy ta funkcja zostala wywolana, zanim przepelnil sie stos. Pytanie rowniez jest o to jak mozna to przepelnianie przyspieszyc i jak oszacowac na podstawie wynikow wielkosc stosu.

Nie mam pojecia jak sie do tego zabrac, domyslam sie, ze trzeba kombinowac cos z rekurencja. Pomozecie?

#cpp #programowanie
  • 24
  • Odpowiedz
@erwit: Odpowiedz z gory, domyslna wielkosc stosu w msvc to 1MiB, w mingw to (chyba) ok 8MiB. Na linuksie jest to ustawienie systemowe.

Tak, rekurencja moƶe Ci przepełnić stos, ale musisz wziąć pod uwagę wielkość ramki, która moƶe się zmieniać w zaleƶności od kompilatora i flag kompilacji. Ponadto przepełnienie stosu wywali Ci program, nie będziesz mógł wypisać komunikatu błędu (przynajmniej nie za pomocą narzędzi dostępnych w standardowym C++, coś system-specific będziesz
  • Odpowiedz
@Vetinari: Ale tak co najwyƶej sprawdzi głębokość rekurencji. No i ogranicza się do konkretnego systemu. Chociaƶ w sumie samo wspomnienie stosu zamyka go w implementacjach uƶywających stosu (stadnard C++ nie wspomina o takim wynalazku ani słowem).
  • Odpowiedz
@WolverinePL: @Vetinari: @KrzaQ2: Poczytalem sobie troche o sygnalach w unixie, ktore byly sa dla mnie czyms zupelnie nowym, swietna rzecz. Zaczalem pisac moj program, lecz juz na samym poczatku napotkalem na komplikacje:

#include /* standardowe funkcje UNIXowe, takie jak getpid() /

#include / różne typy definicji, jak np. pid_t */

#include /* nazwy sygnałów, makra i prototyp funkcji kill() */

#include

int f();

int g();

int g()

{

f();
  • Odpowiedz
@KrzaQ2:

kurcze poprawilem wedlug Twoich wskazowek (przynajmniej tak mi sie wydaje), ale dalej nie dziala :(

'#include /* standardowe funkcje UNIXowe, takie jak getpid() /

#include / różne typy definicji, jak np. pid_t */

#include /* nazwy sygnałów, makra i prototyp funkcji kill() */

#include

void wypisz(int signum) //to jest moj signal hanler

{

signal(SIGSEGV,wypisz);

std::cout<<" przepelnilo sie ";

std::cout<
}

int f();

int g();

int g()

{

f();

}
  • Odpowiedz
@KrzaQ2: @Vetinari: @WolverinePL:

Okej troche pokombinowalem i wynik jest taki: jezeli wywoluje z maina void kupa(); to dziala, tzn, przechwytuje sygnal, a jezeli f(); to nie przechwytuje.

Macie pomysl dlaczego tak jest?

'#include /* standard I/O functions /

#include / standard unix functions, like getpid() /

#include / signal name macros, and the signal() prototype /

#include

/ first, here is the signal handler /

void wypisz(int signum)
  • Odpowiedz
@erwit: Ciekawe :) Wydaje mi sie, ze wytlumaczenie tego jest dosyc prozaiczne: jako, ze skonczyl sie stos to nie mozna wywolac signal handlera - to w sumie jest zwykla funkcja w userspace z takim samym abi jak wszystko inne :)
  • Odpowiedz
@erwit: Z dwoch powodow:

- stos w x86 sie dekrementuje jak sie cos wsadza na niego

- jak wolasz funkcje to jest uzywany po ludzku PUSH, czyli przesuwa sie ESP, jak piszesz poza stos (tak jak w kupa()), to po prostu tam piszesz, ESP w dalszym ciagu wskazuje na poprawny obszar stosu
  • Odpowiedz
@WolverinePL: okej a co przesuwa ta funkcja?

kupa() jest mi do niczego nie potrzebna, zalezy mi na dzialaniu f();

Wydaje mi sie, ze tylko rekurencja moge rozwiazac to zadanie.

Przypominam tresc, zebys nie musial scrollowac:

"Mikrobki musze napisac funkcje void stack() ktora bedzie powodowala przepelnienie sie stosu i w momencie gdy do tego dojdzie, program bedzie przerywany, a na ekranie zostanie wypisany stosowny komunikat (wewnatrz programu, nie przez kompilator). Main() ma
  • Odpowiedz
@WolverinePL: >Rozmiar stosu możesz oszacować odejmując wartość wskaźnika do zmiennej funkcji od zmiennej np w main(). Oczywiście to implementation specific, jak całe to zadanie :P

moglbys przyblizyc jak to ma wygladac?
  • Odpowiedz
okej a co przesuwa ta funkcja?


@erwit: Niczego nie przesuwa, po prostu piszesz poza obszar stosu. Abstrakcyjnie to dziala tak: masz sobie jakis fragment pamieci przydzielonej na stos, powiedzmy, ze jest on pomiedzy adresami 100 a 200, potem masz "zmienna", o nazwie ESP i poczatkowo ma ona wartosc 200. Jak wolasz funkcje to wrzucasz rozne rzeczy na stos, tzn:

- zapisujesz swoja wartosc pod adresem z ESP (200)

- dekrementujesz ESP
  • Odpowiedz