37 votes

Pourquoi Windows 64 bits ne peut-il pas annuler les exceptions utilisateur-noyau-utilisateur?

Pourquoi ne peut-64-bits de Windows détendre la pile pendant une exception, si la pile traverse la frontière noyau - lors de la 32 bits de Windows peut?

Le contexte de l'ensemble de cette question vient:

Le cas de la disparition OnLoad exception de l'utilisateur en mode de rappel des exceptions en x64

Arrière-plan

Dans Windows 32 bits, si je jette une exception dans mon utilisateur en mode code, qui a été appelée à partir d' un noyau en mode code, qui a été appelé à partir de mon utilisateur en mode code, e.g:

User mode                     Kernel Mode
------------------            -------------------
CreateWindow(...);   ------>  NtCreateWindow(...)
                                   |
WindowProc   <---------------------+                                   

la gestion Structurée des exceptions (SEH) dans Windows pourrez vous détendre de la pile, le déroulement de retour à travers le noyau de la mode, de retour dans mon code d'utilisateur, où je peux gérer l'exception, et je vois un valide trace de la pile.

Mais pas en version 64 bits de Windows

Les éditions 64 bits de Windows ne peut pas ce faire:

Pour de complexes raisons, on ne peut pas propager l'exception de retour sur les systèmes d'exploitation 64 bits (amd64 et IA64). Cela a été le cas depuis le premier de 64 bits version de Server 2003. Sur x86, ce n'est pas le cas – l'exception est propagée à travers le noyau de limite et de marche les images en arrière

Et depuis il n'y a aucun moyen de remonter fiable trace de la pile dans ce cas, l'dû prendre une décision: vous permettre de voir la non-absurde d'exception, ou de le cacher complètement:

Le noyau des architectes de l'époque décide de prendre le conservateur AppCompat-approche amicale – masquer l'exception, et espérer pour le mieux.

L'article continue à parler de la façon dont c'était la façon dont 64 bits tous les systèmes d'exploitation Windows s'est comporté:

  • Windows XP 64-bit
  • Windows Server 2003 64-bit
  • Windows Vista 64-bit
  • Windows Server 2008 64-bit

Mais à partir de Windows 7 (et Windows Server 2008), les architectes ont changé leur esprit, en quelque sorte. Pour seulement les applications 64 bits (pas les applications 32 bits), ils (par défaut) arrêt de la suppression de ces utilisateur-kernel-utilisateur exceptions. Donc, par défaut, sur:

  • Windows 7 64-bit
  • Windows Server 2008

toutes les applications 64 bits va voir ces exceptions, où ils n'ont jamais utilisé les voir.

Dans Windows 7, lorsqu'un natif x64 application se bloque dans ce mode, l' Assistant Compatibilité des programmes en est informé. Si l'application n'a pas un Windows 7 Manifeste, nous montrons une boîte de dialogue vous informant que l'APC a mis en place une Application de Compatibilité de la cale. Qu'est-ce que cela signifie? Cela signifie, que la prochaine fois que vous exécutez votre application, Windows va émuler le Serveur 2003 de comportement et de faire de l'exception disparaître. Gardez à l'esprit, que l'APC n'existe pas sur le Serveur 2008 R2, donc cet avis ne s'applique pas.

Donc, la question

La question est pourquoi est 64-bits de Windows incapable de se détendre une pile par l'intermédiaire d'un noyau de transition, tandis que les éditions 32 bits de Windows?

Le seul indice est:

Pour de complexes raisons, on ne peut pas propager l'exception de retour sur les systèmes d'exploitation 64 bits (amd64 et IA64).

L'astuce est qu'il est compliqué.

je ne peut pas comprendre l'explication, car je ne suis pas un développeur du système d'exploitation - mais j'aimerais un coup à savoir pourquoi.


Mise à jour: Correctif pour arrêter la suppression des applications 32 bits

Microsoft a publié un correctif permet aux applications 32 bits pour aussi n'ont plus les exceptions supprimée:

KB976038: les Exceptions sont générées à partir d'une application qui s'exécute dans une version 64 bits de Windows sont ignorés

  • Une exception est levée dans une routine de rappel s'exécute en mode utilisateur.

Dans ce scénario, cette exception ne cause pas de crash de l'application. Au lieu de cela, l'application entre dans un état incohérent. Ensuite, l'application renvoie une autre exception à la règle et se bloque.

Un mode utilisateur en fonction de rappel est généralement défini par l'application de la fonction qui est appelée par un composant de mode noyau. Exemples de mode utilisateur des fonctions de rappel sont Windows procédures et des procédures hook. Ces fonctions sont appelées par Windows pour traiter les messages Windows ou Windows crochet événements.

Le correctif vous permet ensuite d'arrêt de Windows de manger les exceptions à l'échelle mondiale:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
DisableUserModeCallbackFilter: DWORD = 1

ou par application:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Notepad.exe
DisableUserModeCallbackFilter: DWORD = 1

Le comportement a également été documentée sur XP et Server 2003 dans KB973460:


Un soupçon

j'ai trouvé une autre astuce lorsque l'on étudie à l'aide de xperf pour capturer les traces de pile sur une version 64 bits de Windows:

La pile de la Marche dans Xperf

Désactiver La Pagination De L'Exécutif

Pour le traçage de travailler sur une version 64 bits de Windows, vous devez définir la DisablePagingExecutive clé de registre. Cela indique au système d'exploitation pas à la page pilotes en mode noyau et le système de code sur le disque, ce qui est une condition préalable pour l'obtention de 64 bits piles d'appels à l'aide de xperf, car 64 bits pile de la marche dépend de métadonnées dans le fichier exécutable images, et dans certains cas, le xperf pile à pied de code n'est pas autorisé à toucher paginées pages. Exécutant la commande suivante à partir d'une invite de commande élevée permettra de définir cette clé de registre pour vous.

 REG ADD "HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management" -v 
 DisablePagingExecutive -d 0x1 -t REG_DWORD -f

Après la définition de cette clé de registre, vous devez redémarrer votre système avant de pouvoir enregistrer les piles d'appels. Avoir cet indicateur signifie que le noyau de Windows verrous plus de pages en RAM, donc ce sera probablement consommer environ 10 MO d'un supplément de mémoire physique.

Cela donne l'impression que dans Windows 64 bits (et uniquement en version 64 bits de Windows), vous n'êtes pas autorisé à pied les piles du noyau, car il pourrait y avoir des pages sur le disque.

16voto

Paul Betts Points 41354

Je suis le développeur qui a écrit ce Correctif un loooooooong moment il y a ainsi que le blog. La raison principale est que la totalité du fichier de registre n'est pas toujours capturées lors de la transition dans l'espace du noyau, pour des raisons de performances.

Si vous faites une normale syscall, le x64 Application Binary Interface (ABI) vous demande seulement de préserver la non-volatile registres (semblable à une normale de l'appel de fonction). Cependant, correctement déroulement de l'exception nécessite que vous ayez tous les registres, de sorte qu'il n'est pas possible. Au fond, c'est un choix entre perf critique du scénario (c'est à dire un scénario potentiellement arrive des milliers de fois par seconde) par rapport à 100% correctement la manipulation d'un pathologiques scénario (un accident).

Bonus De Lecture

9voto

valdo Points 7322

Une très bonne question.

Je peux donner un indice de pourquoi "propagation" une exception à travers le noyau de l'utilisateur frontière est quelque peu problématique.

Citation de votre question:

Pourquoi ne peut-64-bits de Windows détendre la pile pendant une exception, si la pile traverse la frontière noyau - lors de la 32 bits de Windows peut?

La raison en est très simple: Il n'y a pas une telle chose comme "pile traverse noyau de la frontière". L'appel d'une fonction en mode noyau est en aucun cas comparable à une fonction standard d'appel. Il n'a rien à voir avec la pile d'appel en fait. Comme vous le savez probablement, en mode noyau de la mémoire est tout simplement pas accessible à partir du mode utilisateur.

L'invocation d'une fonction en mode noyau (aka syscall) est mis en œuvre par le déclenchement d'une interruption logicielle (ou un mécanisme similaire). Un utilisateur de code en mode met les valeurs dans les registres (qui permettent d'identifier le besoin de services mode noyau) et appelle un PROCESSEUR d'instructions (comme sysenter) qui transfère le CPU en mode noyau et passe le contrôle à l'OS.

Ensuite, il y a un code en mode noyau qui gère la demande de syscall. Il s'exécute dans une autre pile en mode noyau (qui n'a rien à voir avec le mode utilisateur de la pile). Après que la demande a été traitée - le contrôle est renvoyé à l'utilisateur en mode code. Selon le syscall le mode utilisateur, l'adresse de retour est peut-être celui qui a appelé le noyau de mode de transaction, ainsi que cela peut être différente de l'adresse.

Parfois, vous appelez une fonction en mode noyau que "dans le milieu" doit invoquer un utilisateur en mode appel. Il peut ressembler à une pile d'appel, composée d'un utilisateur-noyau-le code de l'utilisateur, mais c'est juste une émulation. Dans un tel cas, le code en mode noyau transfère le contrôle à un utilisateur en mode code qui enveloppe votre utilisateur en mode fonction. Ce wrapper code appelle la fonction, et dès son retour déclenche un mode noyau de transaction.

Maintenant, si l'utilisateur le code de mode "invoqué à partir du kernelmode" soulève une exception - c'est ce qui devrait se produire:

  1. Le wrapper en mode utilisateur code gère l'exception SEH (c'est à dire les arrêts de sa propagation, mais la performance n'est pas le déroulement de pile encore).
  2. Transmet le contrôle en mode noyau (OS), comme dans un flux de programme normal de cas.
  3. Kenrel de code en mode répond de façon appropriée. Il termine le service demandé. Selon qu'il y a un mode utilisateur exception - le traitement peut être différent.
  4. Après le retour au mode utilisateur - le code en mode noyau peut préciser s'il y avait une exception imbriquée. Dans le cas d'une exception de la pile n'est pas restauré à son état d'origine (puisqu'il n'y a pas de dénouement encore).
  5. En mode utilisateur, le code vérifie si il y avait une telle exception. Si c'était - la pile d'appel est forgé pour inclure les utilisateurs imbriqués en mode d'appel, et que l'exception se propage.

De sorte que l'exception qui traverse le noyau de l'utilisateur frontière est une émulation. Il n'y a pas une telle chose en mode natif.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X