Ahoj programátoři, potřeboval bych zase jednou trochu poradit.
Mám program v TP 7, real mód. Vytvářím poměrně dlouhý spojový seznam s prvky o velikosti 8 B (vím, že ve skutečnosti se pro každý alokuje 16 B) a potřebuju spolehlivě ošetřit situaci, kdy zaplní celou paměť. Před každým použitím New na vytvoření nového prvku si Maxavailem zkontroluju, jestli je na něj dost paměti; pro jistotu to beru s rezervou a jestli není volných aspoň 64 B, tak už nic nealokuju. Teoreticky je všechno v pořádku, většinou takhle zaplnění paměti odchytím, zpracuju a žádný Heap Overflow se nekoná. Jenže cca ve 30% případů mi program spadne s windowsí hláškou "program se pokusil provést nepřípustnou instrukci a bude ukončen", což znamená, že někde zapisuju do nealokované paměti. Jenže nic takového tutově nedělám.
Takže otázka zní: může třeba nějak kolidovat hromada se zásobníkem? Že bych třeba normálně na hromadě alokoval proměnnou, zapsal bych do ní, ale přepsal bych tím něco v zásobníku, třeba lokální proměnné nebo návratovou adresu nějaké procedury?
P.S.: kdybych to chtěl dělat ve FP nebo Delphi, tak bych to udělal, jenže nechci, tak mě na ně prosím neodkazujte.
Fórum › Pascal
Nepřípustná Instrukce při přeplnění paměti
Moje stránka.
$M jsem zkoušel. Hromadu jsem skrouhnul postupně až na 50 kB, ale nepomohlo to. Stejně tak změna velikosti zásobníku.
Memavail mě původně nenapadl. Takže jsem ho zkusil (přidán do všech podmínek), ale nezabralo to. Ještě jsem zkusil zvětšit rezervu (když není volných aspoň 100 B, tak nealokuju), ale jsem na tom pořád stejně.
Problém je, že mi tady nepomůže krokování a watche, protože ta chyba se objevuje víceméně náhodně. Někdy se zaplněnou paměť odchytit podaří, jindy ne. Už jsem viděl hlášky "program se pokusil provést nepřípustnou instrukci", "program vyvolal výjimku na adrese...", "program porušil všeobecnou ochranu", "program vyvolal blíže neurčenou výjimku" a pár dalších. Podle té první bych tipoval, že se (občas) CS:IP dostane na nějaký nesmysl, což znamená buď že jsem si přepsal kus programu v code segmentu (což je blbost), nebo že se z těla té procedury přepsala její návratová adresa uložená v zásobníku a procedura se pak retla neznámo kam. Vím, že zásobník se plní směrem dolů (push snižuje SP a pop ho zvyšuje), ale nevím, kde začíná ani kde by měl normálně končit a jestli TP nějak kontroluje, jestli nekoliduje s hromadou a jestli New nealokuje paměť na území zásobníku.
Ještě si s tím zkusím chvíli hrát, a uvidíme, jak to dopadne.
Hmm... a nebo... ... právě mě napadla brutální myšlenka:
procedure ...(...);
Begin
asm
pop návratovou adresu ze zásobníku do nějakých proměnných
push zase všechno zpátky na zásobník, aby procedura nic nepoznala
end;
...tady někde ta chyba vzniká...
asm
pop totéž co na začátku, ale získaná data zahodit
push místo nich ty uložené původní hodnoty
end;
End;
Jestli selže všechno ostatní, tak zkusím i tohle. Ale asi by to nebylo nic jednoduchého, protože ta procedura není pod direktivou Assembler, je docela dlouhá, má dvě lokální podprocedury a hromadu lokálních proměnných, takže najít v zásobníku návratovou adresu bude asi docela dřina... no nic, tohle bude až poslední možnost.
Moje stránka.
Vyřešeno.
Já hlava dubová, nakonec to všechno způsobil úplně jiný úsek kódu než jsem původně myslel (jedno zákeřně podteklé statické lokální pole), ten spojový seznam už byl OK.
Závěr: Maxavail funguje spolehlivě, kolize zásobníku a hromady netřeba se obávat. A příště nebudu tolik pospíchat s psaním do fóra :-].
Moje stránka.
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Uvolnění paměti při běhu v PHP. — založil jinaq
QT Creator a RDRAND instrukce — založil Seph
Instrukce ATtiny 2313 — založil _Radek_
Fáze instrukce - vytváření vlastní instukce — založil antybart
Zastavení kódu při změně proměnné při debugování ve VS2015 — založil vesi
Moderátoři diskuze