vinduer - Tænk eksperiment med \_\_stdcall og beskadiget stak (C ++)

Indlæg af Hanne Mølgaard Plasc

Problem



Mit hjerte vandrede i dag om emnet for funktionspegerne, og jeg kom op på følgende scenarie i mit hoved:


\_\_stdcall int function (int)
{
    return 0;
}

int main()
{
    (*(int(*)(char*,char*))function)("thought", "experiment");
    return 0;
}


AFAIK denne kode ville ødelægge stakken, så hvilke typer problemer kan jeg se på, hvis jeg kørte denne kode?


Jeg undersøger mig selv, men jeg er væk fra min dev-maskin i en uge.


EDIT: Hold på et sekund, jeg har tænkt lidt mere. Som det er blevet observeret i kommentarerne, var hensigten med denne kode at have en parameter tilbage på stakken, når alt er sagt og gjort (opkalder sætter to params på stakken, callee - forventer kun en parametre - kun en gang). Men da jeg ikke har nævnt kaldkonventionen, kaster jeg væk stdcall, i hvert fald fra opkaldets synspunkt? int funktion (int) vil stadig pop en param fra stakken, men ringer opkalderen tilbage til at tænke funktionen er \_\_cdecl (standard) på grund af støbningen? (dvs. tre samlede parametre dukkede?)


EDIT2: Svaret på det andet spørgsmål, som bekræftet af Rob, er ja. Jeg ville nødt til at genoprette \_\_stdcall, hvis jeg ønskede at forlade en param på stakken:


(*(\_\_stdcall int(*)(char*,char*))function)("thought", "experiment");

Bedste reference


Du ringer funktionen som om den er \_cdecl, hvilket betyder, at opkalderen skubber argumenterne og rydder op i stakken.


Modtagelsesfunktionen er \_stdcall, hvilket betyder, at callee renser op i stakken. Callee forventer et enkelt argument, så pop 4 bytes fra stakken.


Når funktionen vender tilbage, så ringer opkaldet to pegere (har tidligere trykket på to peger), så din stack bliver beskadiget med 4 byte.


Begge kaldkonventioner bruger samme returmekanisme, og har de samme registerregler (eax, ecx og edx er ikke bevaret). Se wikipedia for flere detaljer. [3]


Afhængigt af stackrammens layout og justering kan denne fejlpasning medføre en række effekter. Hvis du er heldig, så kommer du væk med den. Hvis ikke, kan du ødelægge returadressen til din hovedfunktion, hvilket får programmet til at gå ned, når det forgrener sig til, hvem der ved. Hvis kompilatoren har injiceret en slags stakvagt for at fange korruption, vil det sandsynligvis opdage dette og afbryde programmet.

Andre referencer 1


Nej, det vil helt sikkert ikke forårsage en blå skærm. Ingen brugertilstandsproces er i stand til at gøre det. Selv hvis en sådan fejl var i kernel-mode kode, ville BSOD kun ske efter at have adgang til ugyldig hukommelse eller passere forkerte argumenter til en funktion.


Du ødelægger simpelthen privat hukommelse af din proces, og korruptionen kan (eller måske ikke) senere resultere i en ugyldig operation (f.eks. Bortføring af en pointer, der peger på ugyldig hukommelse). Når dette sker, afslutter operativsystemet din proces, men ikke før.

Andre referencer 2


Jeg tror, ​​du ville have 'udefineret adfærd' i dette tilfælde.


Fra C-standarden: (Jeg antager, at det er det samme i C ++) [4]



  768 Hvis
  en konverteret peger bruges til at kalde en
  funktion, hvis type ikke er kompatibel
  med den spidse-typen, adfærd
  er udefineret.



Rediger: På det meste operativsystem ville denne type fejl ikke medføre problemer i hele dit operativsystem. Men det ville medføre udefinerede problemer i dit program. Det ville være meget svært for et brugermodusprogram at kunne forårsage en blå skærm.