Fehler in ATLTHUNK.DLL führt auf Windows 10 (64bit) unter bestimmten Umständen zu zufälligen Crashes von Anwendungen

Wer es schnell mag, kann gleich den Beitrag und technische Details auf Stack Overflow lesen:
http://stackoverflow.com/questions/41741448/random-crashes-on-windows-10-64bit-with-atl-subclassing

Hier möchte ich etwas ausführlicher, die Story dazu erzählen, eine Story aus dem ganz „normalen“ Leben eines Programmierers 😉

Letztes Jahr stellen wir in der Firma produktiv von VC-2013 auf VC-2015 um. Wir haben eine relativ große Anwendung, die im Kern, MFC und ATL verwendet. Unsere Anwendung zeigt Informationen in vielen Tabs und Dialogen an. Mehr als 256 Fenster sind da keine Ausnahme und eher die Regel als eine Seltenheit.

Unsere Anwendung erzeugt bei Crashes automatisch volle Dumps auch bei Kunden. Für unsere Qualitätssicherung ein Muss und ein Segen.
Bereits in der Alpha und Beta Phase hatten wir auf manchen Rechnern ein eigentümliches Phänomen. Unser Programm startete und erzeugte Fenster und auf einmal kam es zu einem Absturz bei oft ganz einfachen Windows API Funktionen, die ein Fenster verwendeten und die alle ausnahmslos letzten Endes dazu führten, dass eine Nachricht an ein Fenster gesendet wird. Der Stack war nichtssagend und schien zerstört. Die Dumps für die einzelnen User waren aber fast immer glich.
Das Problem trat in Release und Debug Builds auf.

Der Horror für jeden Programmierer. Nicht nachzuvollziehende Crashes auf manchen Rechnern. Heapfehler? Wilder Zeiger? Buffer-Overrun? Nichts was man gebrauchen kann… aber kein Analysetool was wir verwendeten schlug Alarm…

Nach Sammlung von mehreren Dumps waren die Crashes immer wieder an ähnlichen Stellen und fast immer alle sofort nach Programmstart. Betroffen in der Regel alles Windows 10 64bit Maschinen auf dem aktuellen Softwarestand, meistens hatten diese Maschinen 8GB und zum Teil weitaus mehr Speichern und es waren ausnahmslos schnelle Intel i7 verschiedener Generationen. Und in virtuellen Maschinen konnte ich das bisher nicht nachvollziehen.

Interessant, war, dass ich diese Crashes auch auf meiner Entwicklungsmaschine hatte. Manchmal…
Nach einigen Tests konnte ich sagen. Entweder tritt der Fehler auf und solange der Rechner gestartet ist kann man es manchmal nachvollziehen, oder der Fehler tritt eben nicht auf und man hat Ruhe vor ihm. Dann hatte ich mir 3 Tage hintereinander – ohne Rechnerneustart – mit Debug-Session auf Debug-Session eine Spur erarbeitet. Es war immer das 257 Fenster, dass gesubclassed wurde (mit ATL Thunking) oder erzeugt wurde (ATL Fenster), dass zum Crash führte.
Insofern war es bei jedem User auch immer ein ähnlicher Dump, weil der Fensteraufbau ja bei jedem User individuell war.

Am Ende des dritten Tages hatte ich einen Testcode, der den Fehler in der aktuellen Windows Session meines Rechners und meinen Programm zu 100% nachvollziehbar machte. Ich verschob den Testcode immer weiter in einem Programm nach vorne, bis ich bei InitInstance ankam.
Ups. Es liegt nicht an meiner Software.
Dann isolierte ich den Testcode in eine eigenes Programm und konnte den Bug in einem minimalen Sample nachstellen.

Zeit für einen Support-Case bei Microsoft und eine Anfrage auf stackoverflow.com (das war am 19.01.2017).

Mit dem Case hatte ich natürlich auch einen Workaround. Ich musste nur einfach die atlthunk.dll nicht benutzen und auch das ging mit einer einfachen Änderung in der atlstdthunk.h. (Auskommentieren des defines USE_ATL_THUNK2).

Die Kommunikation mit Microsoft gestaltete sich nicht einfach. Aber ich hatte zumindest einen konstruktiven MS Mitarbeiter aus Indien erwischt. Dumps konnte ich Microsoft liefern, auch den Crash direkt in einer Session zeigen. Code hatten sie auch, aber der Bug war bisher nicht bei Ihnen nachvollziehbar. Das trieb mich fast in die Verzweiflung. Natürlich musste alles andere ausgeschlossen werden.. Virenscanner, andere Software… etc…
Dennoch kein Repro auf eine Microsoft Maschine. Allerdings weiß ich nicht wie „intensiv“ da gesucht wurde.

Dann endlich ein Lichtblick auf stackoverflow.com. Eugene konnte den Bug nachvollziehen. Endlich.
Und nachdem ich wusste, dass es mit der bevorzugten Ladeadresse zu tun hatte, konnte ich auch meinen Code erweitern und mit 100% Wahrscheinlichkeit den Crash erzeugen.
Wenn also an der bisher bevorzugten Ladeadresse der atlthunk.dll kein Speicher zur Verfügung liegt und sofort wieder eine Relocation notwendig wird, dann kracht es. Lustig, da wir ja durch ASLR sowieso keine festen Ladeadressen haben, aber es gibt innerhalb einer Windows Session dennoch eine „bevorzugte Ladeadresse“.

Jetzt bin ich gespannt auf Microsoft…
Denn defakto kann jede Software die mit dem VC-2015 und VC-2017 Compiler und der ATL kompiliert wurde von diesem Problem betroffen sein.

PS: Man entschuldige mir Ungenauigkeiten oder auch falsche Begrifflichkeiten…
Bis heute habe ich den Fehler immer noch nicht ganz verstanden und ganz sooo tief lebe ich im Kernel von Windows doch nicht. 😀

PPS: Ich werden den Artikel auf stackoverflow.com aktuell halten.

Nachtrag 01.03.2017:

  • Microsoft hat bestätigt, dass es sich um um einen Bug handelt.
  • Der Bug soll in der nächsten Windows 10 Version (RS2) gefixed sein.
  • Nachteil: Ich werde wohl mit der Änderung der ATL leben müssen, denn auch andere Windows Versionen sind von diesem Fehler betroffen.