Question

Mon esprit errait aujourd'hui sur le thème des pointeurs de fonction, et je suis venu avec le scénario suivant dans ma tête:

__stdcall int function (int)
{
    return 0;
}

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

AFAIK ce code pourrait corrompre la pile, donc quels types de questions que je pourrais regarderais si je courais ce code?

Je ferais moi-même enquête mais je suis loin de ma machine dev pendant une semaine.

EDIT: Attendez une seconde, j'ai pensé un peu plus. Comme cela a été observé dans les commentaires, l'intention de ce code était d'avoir un paramètre à gauche sur la pile quand tout est dit et fait (l'appelant met deux params sur la pile, callee - attendant qu'un seul param - apparaît un seul arrêt ). Cependant, étant donné que mon casting ne fait pas mention de la convention d'appel, que je stdcall loin CASTING, au moins du point de vue de l'appelant? fonction int (int) toujours pop un de la pile param, mais ne l'appelant revenir à penser la fonction est __cdecl (la valeur par défaut) en raison de la distribution? (À savoir trois au total params sauté?)

EDIT2: La réponse à cette deuxième question, comme l'a confirmé par Rob, est oui. Je dois retraiter __stdcall si je voulais laisser un param sur la pile:

(*(__stdcall int(*)(char*,char*))function)("thought", "experiment");
Était-ce utile?

La solution

Vous appelez la fonction comme si elle _cdecl ce qui signifie que l'appelant repousse les arguments et nettoie la pile.

La fonction de réception est _stdcall ce qui implique l'appelé nettoie la pile. Le callee attend un seul argument si sautera 4 octets de la pile.

Lorsque la fonction retourne l'appelant sera alors crèveront deux pointeurs (ayant précédemment poussé deux pointeurs), de sorte que votre pile est corrompu par 4 octets.

Les deux conventions d'appel utilisent le même mécanisme de retour, et ont les mêmes règles de registre (EAX, ECX et EDX ne sont pas conservés). Voir wikipedia pour plus de détails.

En fonction de la mise en page du cadre de la pile et l'alignement ce décalage pourrait causer un certain nombre d'effets. Si vous êtes chanceux, vous obtenez avec elle. Sinon vous pourriez gâcher l'adresse de retour de votre fonction principale, ce qui provoque un plantage du programme quand il se ramifie à qui sait où. Si le compilateur a injecté une sorte de protection de la pile pour attraper la corruption alors il détectera probablement cela et abandonner le programme.

Autres conseils

Non, ce ne sera certainement pas provoquer un écran bleu. Aucun processus en mode utilisateur est en mesure de le faire. Même si ce bogue était dans le code en mode noyau, le BSOD se produirait seulement après l'accès à la mémoire non valide ou qui passe mal des arguments à une fonction.

Vous êtes simplement corruptrice mémoire privée de votre processus, et la corruption peut (ou non) entraîner plus tard dans une opération non valide (par exemple. Déréférencement un pointeur vers la mémoire non valide). Lorsque cela se produit, le système d'exploitation met fin à votre processus, mais pas plus tôt.

Je pense que vous auriez « un comportement non défini » dans ce cas.

De la C standard : (je suppose qu'il est la même chose C ++)

  

768 Si   un pointeur converti est utilisé pour appeler un   fonction dont le type n'est pas compatible   avec le pointu de type, le comportement   est indéfini.

Edit: Sur la plupart des systèmes d'exploitation, ce type d'erreur ne serait pas causer des problèmes dans l'ensemble de votre système d'exploitation. Mais cela causerait des problèmes non définis dans votre programme. Il serait très difficile pour un programme en mode utilisateur pour pouvoir provoquer un écran bleu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top