Wenn man nicht genau aufpasst mit Overlapped I/O und CancelIo vergisst

Overlapped I/O ist eine Standardtechnik, die ja jeder kennt, der mit Datenquellen arbeitet, die „irgendwann“ mal Informationen liefert, man aber in der Zeit evtl. noch anderes zu tun hat 😉

In meinem Fall, den ich hier schildere, benutzte unser Programm einen Service, mit dem es über Named Pipes kommuniziert. Das entsprechende Modul, ist schon ziemlich alt und hat seit ca. 3 Jahren keine Änderung erfahren. Aber jetzt auf einmal häuften sich Meldungen, dass unser Programm beim Beenden einen UAE auslöst.

Entsprechende Minidumps wurden angefordert und deren Analyse zeigte eigentlich nicht viel wirklich erhellendes.  Es sah alles danach aus, als ob ein Speicherblock freigegeben wird, der bereits freigegeben wurde.
Leider konnte das Szenario in unserem Testfeld nicht einfach nachgestellt werden. Und auch mehrfache Analyse des Sourcecodes brachte erst einmal nichts. Man ist manchmal einfach betriebsblind 🙁

Auffällig war aber, dass diese Meldungen erst vereinzelt auftraten nachdem unsere Software auf VS-2013 Update 3 umgestellt war und diese an Kunden ausgerollt wurde. Und weiterhin konnten wir feststellen, dass alle diejenigen, die diesen Fehler gemeldet haben, relativ leistungsfähige Rechner hatten.

Schließlich gelang es mir, das Szenario auf einem meiner Entwicklungsrechner nachzustellen.

Das passierte:

  1. Das Programm erhielt den Befehl zum Beenden.
  2. Irgendwann wurde auch dem Thread, der mit dem Service interagiert gesagt, dass er sich beim Dienst ausloggen soll.
  3. Der Dienst gibt auch brav den Befehl „Logoff“ an den Service.
  4. Der Thread der in einer Schleife immer auf einen Response des Dienstes wartet beendet sofort.
  5. Und nun erfolgte der Crash.

Die Ursache war ein fehlender CancelIo. Damit das Beenden möglichst schnell vonstatten geht, wurde darauf verzichtet, auf eine Antwort des Services zu warten, ob der Logoff Befehl verstanden wurde, denn kurz danach wird sowieso die Pipe geschlossen. Keine gute Idee in diesem Fall! Das hatte auch den Grund darin, dass

Was ist also passiert ❓

  • Die OVERLAPPED Struktur für den Lesevorgang lag auf dem Stack innerhalb einer while Schleife, die auf verschiedene Events wartet.
  • Die Funktion in der diese Struktur deklariert war wurde aber bereits verlassen.
  • Wenn dann sehr schnell die Antwort des Dienstes kam, wurde in die alte Adresse der OVERLAPPED Struktur ein Wert verändert.
  • … und damit wurde der Stack an dieser Stelle zerstört.

Es waren in meinem Fall nur 4 Bytes und in manchen Fällen würde eine Rücksprungadresse verändert und es kam zum Crash. In anderen Fällen wurde Speicher verändert, der nicht mehr benutzt wurde. Das ganze passierte eben auch nur auf den Systemen, die sehr schnell auf die Antwort des Dienstes reagierten. Kam die Antwort spät genug, war die Änderung des Speichers nicht mehr gefährlich.

Der Fehler blieb jahrelang unentdeckt, weil scheinbar das Stacklayout, das durch den VS-2010 Compiler erzeugt wurde, gegen diesen Fehler unempfindlich war, weil nur Speicher verändert wurde, der nicht zu einem Fehler führte.

Was lerne ich daraus:
Wenn ich einen ReadFile mit OVERLAPPED verwende, sollte ich immer darauf achten, dass im Bedarfsfall auch dieser Vorgang abgebrochen wird durch ein CancelIo ❗ Ein CancelIo mehr kann nicht schaden, wenn man den Block verlässt, in der eine OVERLAPPED Struktur definiert war.

Das Update für Microsoft Visual Studio 2010 Service Pack 1 (KB2635973) macht Visual-Studio instabil

Ich habe eindeutig und nachvollziehbar die Erfahrung gemacht, dass dieser Fix Update für Microsoft Visual Studio 2010 Service Pack 1 (KB2635973) Visual-Studio 2010 instabil macht. (siehe auch http://support.microsoft.com/?kbid=2635973)

Ich habe seit längerer Zeit immer wieder Abstürze in Visual-Studio. Nachvollziehbar ist in den Dumps zu sehen, dass dies immer dann passiert wenn der Garbage-Collector anläuft. Es ist auch immer die selbe Stelle in den selben Modulen.

Oft verschwindet eine offene Visual-Studio Instanz, die im Hintergrund offen war, während ich z.B. in Outlook eine Email schreibe einfach vom Bildschirm und startet erneut. Ich sehe dann ein „blinken“ in der Startleiste. Die Solution ist natürlich geschlossen. Dateien wurde nicht gesichert (können aber meistens recovert werden).
Oder ich arbeite in einem großen Projekt und Tippe meistens eine Klammer, einen Punkt oder einen Strich-Größerzeichen und Intellisense springt an und crashed meine Anwendung.

Ich habe mir sogar die Mühe gemacht 4 Arbeitstage ohne Addins zu arbeiten um zu prüfen ob ein Addin der Verursacher war. Ich kam mir ohne VA-X und Powertools wie Fingeramputiert vor. Dennoch kam es immer wieder zu Crashes, der genau gleichen Art. Meistens immer in großen Projekten.

Ich habe natürlich einen Case dazu, auf dem sich aber eigentlich nichts tut, obwohl Microsoft haufenweise Dumps von mir bekommen hat:
http://connect.microsoft.com/VisualStudio/feedback/details/635653/crash-while-navigating-in-vs-2010-and-crashes-when-vs-is-inactive-in-the-background

Allerdings bekam ich jetzt einen Tipp von einem Microsoft Mitarbeiter in diesem Case, den oben genannten  Fix zu deinstallieren.
Die Crashes sind nicht weg, aber sind eindeutig weniger geworden ❗
Wenn man sich die Daten ansieht merkt man auch schnell, dass ich diesen Case auch veröffentlicht, bevor der besagte Fix KB2635973 herauskam.

Tipp: Wer also mit einer Englischen VS-Version arbeitet sollte diesen Hotfix meiner Meinung nach deinstallieren ❗

Kleines Resumé aus dem C++ Day am 07.02.2012 in Bad Homburg v.d.H.

Hier ein paar Gedanken zum C++Day in Bad Homburg. v.d.H.. Die Zeilen hier geben meine ganz persönliche Meinung wieder. Kommentare (auch mit abweichender Meinung) sind hier gerne gesehen.

Es hat sich gelohnt:

  • alleine schon weil (ungeplant und überraschenderweise) 2 MS-Mitarbeiter aus dem Produktteam anwesend waren.
  • Und man dadurch detailiert und direkt einige Fragen loswerden konnte.

Zu den Vorträgen:

  • Interessent, aber eigentlich nicht wirklich viel neues was zu sehen war.
    Große Teile habe ich in den Previews TR1  für VS-2008 (Featurepack) und VS-2010 schon in 2008+2009 gesehen 😉
  • Wieder etwas zu viel Gewicht auf Parallelisierung. OK. Es ist ein Thema. Aber ehrlich gesagt wüsste ich nur einen kleinen Teilbereich meiner aktuellen Projekte wo ein Einsatz dieser Tools Sinn macht.
  • Schön zu sehen, dass sich endlich auch etwas mehr im ALM Bereich für C++ tut.

Zwischen den Zeilen herausgehört (und manchmal ganz offen ausgesprochen):

  • Man kann wirklich hören, dass Microsoft der Sprache C++ neuen Raum gibt.
  • Ressourcen sparen zu entwickeln ist eben immer noch leichter mit einer Hochsprache wie C++. Das wusste ich eigentlich schon immer, aber manch einer hat das irgendwie im .Net-Trubel übersehen 😉
  • Die neuen Features in C++11 machen es leichter „fehlerfreie“ Programme zu schreiben. Es lohnt unbedingt sich mit den neuen Features auseinanderzusetzen und diese auch zu nutzen.
  • Ja es geht weiter. An den neuen Compiler Features für C++11 wird fieberhaft gearbeitet. Evtl. werden manche Features noch nicht im nächsten Release (VS-2012?) drin sein, aber in einem Featurepack (kennen wir ja schon) wird nachgeliefert.

Augeschnappt habe ich Stimmungen und Stimmen:

  • Es erstaunt mich immer wieder wie oft „alte Dinge“ (TR1), die zum Teil schon VS-2008 SP1 veröffentlicht wurden, immer noch nicht unter den Entwicklern angekommen sind. Es ist erschreckend wie hoch das Beharrungsvermögen auf alten Compilern und Libraries ist.
  •  Es erstaunt mich auch, dass viele Entwickler scheinbar an den neuen Features von C++11 vorbeigehen oder sich nicht wirklich so eingehend damit befassen, dass es auch aktiv genutzt wird.
  • Und es erstaunt mich auch, dass bei den Chefs und Projektverantwortlichen nicht angekommen ist, dass mit C++11 und den neueren Microsoft Compilern, Tools vorhanden sind die wirklich die Produktivitt steigern, wenn man diese auch einsetzt.
  • Für mich deshalb unfassbar wie viele noch VC6 benutzen (oft genug müssen). 😉
  • Es gibt immer noch zu viele Ängste vor dem Umstieg auf neue VS Versionen.
    Meine Erfahrung ist, dass seit VS-2005 ein wechsel auf neue VS-Versionen (2008/2010) spührbar neues gebracht hat, aber kaum Probleme bei der Umstellung mit sich brachte. „Projekte übernommen und es läuft“ war meine Erfahrung.

Was würde ich mir für die Zukunft auf C++ (Days/Konferenzen) wünschen:

  • Schön wäre es, wenn man einmal Sprecher finden würde, die wirklich aktive Projekte betreuen, die in C++ realisiert werden. Leider haben die meisten Sessions von deutschen Sprechern oft etwas künstliches, weil sie oft selbst nicht mehr C++ Projekte betreuen sondern doch eher mit .NET „eigentlich“ ihr Geld verdienen.
  • Nicht selten sind die Vorträge geclonte Vorträge von Sessions die irgendwo anders gehalten wurden.
  • Gut wenn man C++ Gurus als Sprecher findet, aber auch hier wird es oft blutleer weil abgehoben.
    Ich hätte manchmal gerne etwas dazwischen 😉

Grundsätzlich danke an Christian Binder (Microsoft), der sich immer wieder für C++ Veranstaltungen in Deutschland bemüht, obwohl ALM eher sein Thema ist.
Es ist schade, dass Microsoft in Deutschland niemanden Verantwortlichen hat, der wirklich auch mit C++ arbeitet und dem entsprechend auch das Produkt wirklich am Herzen liegt.

PS: Die Folien werden voraussichtlich auf dem Blog von Christian Binder veröffentlicht werden.

PPS: Ich merke selbst für mich, dass ich mir zu wenig Zeit nehme mit neuen Werkzeugen (z.B. Windows 8 Developer Preview) zu spielen um deren Produktivitätsvorteile (und manchmal auch Nachteile) besser zu erkennen. Alleine deshalb kann ich jedem nur empfehlen solche C++Days zu nutzen um wenigstens dadurch über den eigenen Tellerrand hinaus zu gucken. Eigentlich mache ich das viel zu selten.

Visual Studio 2010 komplett entfernen bzw. die Unmöglichkeit es richtig zu tun

Immer wieder mal lese ich von Problemen bei der Installation oder mit Installationen von VS-2010. Ich hatte den Fall noch nie, aber es gibt scheinbar immer wieder Installationen in denen der Wurm drin ist.

VS-2010 installiert eine Unmenge an Komponenten und Programmteilen. Die meisten können einfach deinstalliert/gelöscht werden. Aber es bleiben immer noch ein Haufen DLLs/ActiveX Controls und Registry Einträge und Verweise auf Verzeichnisse. Und leider gibt es für die Visual Studio 2010 keinen richtigen Uninstaller, der auch alle Artefakte löscht und deshalb kann ich gleich zu Anfang sagen, dass man außer der Deinstallation wirklich wenig tun kann.
Eine Reparaturinstallation sollte man aber bei einer bestehenden Installation in jedem Fall einmal, bevor man zu härteren Maßnahmen greift. Die wirkt oft schon Wunder.

Im Netz gibt es das folgende Utility: Visual Studio 2010 Uninstall Utility:
http://archive.msdn.microsoft.com/vs2010uninstall
Das Tool hat drei Operationsweisen die man in dem obigen Link erklärt findet.
Das Tool funktioniert eigentlich ohne Probleme aber benutzt auch nur auf dem MSI Uninstall Prozess auf, und dabei berücksichtigt es nicht einmal Servicepacks. Sollte man also das SP1 von Visual Studio 2010 installiert haben, dann muss man dieses vorher selber entfernen.

Das dieses Tool macht aber auch nur die Arbeit halb. Das erkennt man mit einem schnellen Blick in Registry. Der Ast HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0 wird durch die Deinstallation nicht entfernt und man muß in diesem Fall manuell Hand anlegen.

Wenn man also persistente Probleme mit der VS-2010 Installation hat, die man nicht über die Setup-Logs oder mit Tipps aus den Foren lösen kann, dann bleibt nach meiner Meinung nur der harte Weg den Rechner neu aufzusetzen. Bisher bin ich davon verschont geblieben und meine Installation haben immer von Rechnerwechsel zu Rechnerwechsel gehalten.

4 Termine für Microsoft C++ Infoday 2012

Wer letztes Jahr im Oktober keine Zeit hatte zum C++ Info Day nach München zu kommen, kann dies nun nachholen.

In etwa ähnliche Themen werden an vier verschiedenen Terminen und Standorten von Microsoft kostenlos angeboten:

Die Themen:

  • C++ 11: Modernes C++ im 21. Jahrhundert
  • Parallel-Power in Visual Studio 11: Konzepte und Tools
  • Application Lifecycle Management für C++: Die nächste Generation

Die Termine:

Ich werde 07.02. in Bad Homburg vor Ort sein um ein wenig Networking zu betreiben.
Da es aktuell eigentlich keine C/C++ Community im Netz gibt sehe ich hier die einzige wirklich gute Möglichkeit mit anderen C/C++ Entwicklern ins Gespräch zu kommen.

VS-Tipps & Tricks: Debugger Pseudo Variablen

Die folgenden Variablen helfen mir immer wieder beim Debuggen und zeigen einem während des Debuggens in Watch-Window manch nützliche Information:

  • $TID
    Die Thread ID des aktuellen Threads. Nützlich wenn man mehrere Threads debuggt und bestimmte Threads bei einem Breakpoint identifizieren muss.
  • $HANDLES
    Die Anzahl der aktuell benutzen System-Handles des Prozesses. Handle Leaks lassen sich damit im Debugger leicht überwachen.
  • $ERR
    GetLastError
    leicht gemacht. Schlägt ein WinApi Befehl fehl, dann ist es schön das man sofort beim Debuggen im Watch-Window sehen kann was die Ursache war. Oft genug ist ja im Code selbst kein Aufruf von GetLastError vorhanden oder nötig.

Siehe auch MSDN:
http://msdn.microsoft.com/en-us/library/ms164891.aspx

BTW: WinDbg hat noch einige mehr nette Pseudovariablen:
http://blogs.msdn.com/b/debuggingtoolbox/archive/2008/06/16/special-command-using-variables-and-retrieving-information-through-pseudo-registers.aspx
Schmerzhaft vermisse ich immer wieder $PEB, $TEB, $TPID, $RA im Visual Studio, komisch, dass es die nur im WinDbg gibt.

Für was ist der Makro %(PreprocessorDefinitions) gut ?

In den C++ Compilereinstellungen finden sich ein vorgegebener Makro %(PreprocessorDefinitions) in den C++ Präprozessor Definitionen. Die Verwendung dieses Makros ist nicht ganz offensichtlich.

Dieser Makro sollten in jedem Fall nicht entfernt werden, denn Sie dienen der Übernahme einiger Einstellungen aus der General-Seite für die C++ Projekte. Zum Beispiel werden die Einstellungen für Unicode und MBCS über den Makro %(PreprocessorDefinitions) in die allgemeinen Compiler-Einstellungen übernommen (die entsprechenden Defines sind _UNICODE; UNICODE; _MBCS ).
Erzeugt man eine DLL wird zusätzlich _WINDLL gesetzt.
Setzt man ATL Optionen in der General Seite wird auch über die %(PreprocessorDefinitions) _ATLDLL bzw. _ATL_STATIC_REGISTRY gesetzt oder zurückgesetzt.
Gleiches gilt, wenn die MFC als shared DLL verwendet wird. In diesem Fall wird der Define _AFXDLL zusätzlich gesetzt.

Löscht man also %(PreprocessorDefinitions) dann werden alle diese Einstellungen nicht mehr  korrekt übernommen.

Anmerkung:
Bei dem Linker Makro %(AdditionalDependencies) habe ich eine ähnliche Verwendung vermutet, konnte aber keine direkte Beziehung zur Seite General herstellen.

Obwohl es auch hier Einflüsse auf die Linkereinstellungen gibt bei Änderungen in den General-Einstellungen. Werden allerdings die MFC als zusätzliche Bibliothek ausgewählt werden die Standard-LIBs aus dem SDK komplett entfernt. Hier gibt die MFC Bibliothek selbst vor in welchen zusätzlichen Libs, des SDK gesucht werden soll über #pragma comment(lib,..).

vNext (VS-2011): Im aktuellen Preview kann man keine Programme mehr für XP entwickeln

Es kursiert ja bereits das Windows Developer Preview, also eine virtuelle Maschine mit der man in die nächste Windows 8 und Visual Studio Version hinein schnuppern kann.

Mein Mit-MVP Mike Ryan hat nun bei Tests festgestellt, dass die mit der neuen Visual Studio Version erzeugten Programme, die die MFC 11 und CRT 11 benutzen nicht mehr unter Windows XP laufen ❗ 😮 Aus eigenen Tests kann ich das noch nicht bestätigen.

Das ist mit großer Sicherheit ein Killerkriterium… zumindest ist es das in unserer Firma.
Mich wundert das, vor allem weil der Support für Windows XP auch noch bis 2014 läuft und wenn man Statistiken glauben darf, dann ist die Häufigkeit der Verwendung von Windows XP erst seit Juli diesen Jahres unter die 50% Marke gefallen.

Auf Connect wurde ein entsprechende Bug-Report eröffnet, es gibt hier die Möglichkeit mit den eigenen Stimmen für etwas Widerstand zu sorgen:
https://connect.microsoft.com/VisualStudio/feedback/details/690617
Also bitte gebt Eure Stimme ab!

Da die nächste VS Version vermutlich noch bis Herbst nächsten Jahres auf sich warten lässt kann man nur hoffen, dass sich das ändern wird.

Nachtrag 26.09.2011: Weitere Details zu den fehlenden Funktionen siehe Kommentare
Nachtrag 29.09.2011: Es scheint kein Zufall oder eine vorläufige Beschränkung zu sein. Der Bug wurde mit By Design geschlosen ❗ Ich kann dennoch nur raten auf deisem case weiter mit Stimmen abzugeben.

Änderungen in den VC-Libraries des Sicherheitsupdates vom 09.08.2011

Eigentlich kann man es kein Sicherheitsupdate nennen. Ich sehe  eigentlich nur eine sicherheitsrelevante Änderung in:

  • atltransactionmanager.h (ATL)
    Hier wird das Laden der ktmw32.dll jetzt mit einer neuen Funktion AtlLoadSystemLibraryUsingFullPath durchgeführt, die in atlcore.h hinzugefügt wird. Diese Funktion lädt eine DLL nur aus dem Windows-System Verzeichnis. Damit wird Binary-Planting verhindert, aber dies betrifft eigentlich nur Windows Vista / 7 / 2008 Windows 2003 und Windows XP (Nachtrag am 18.08. siehe dazu Kommentar von Stefan Kuhr) und diejenigen die den Kernel Transaction Manager mit der ATL nutzen.

Bugfixes habe ich folgende gefunden:

  • afxtoolbarimages.cpp (MFC)
    In CPngImage::LoadFromBuffer wurde bei der Verwendung dieser Funktion in Speicherblock eines Streams nicht freigegeben (falsche Nutzung von CreateStreamOnHGlobal).
  • dbcore (MFC / ODBC)
    In CRecordset::BuildUpdateSQL in der ODBC Implementierung, wird bei Abfrage eines Cursornamens ein Puffer von 18 Zeichen Länge verwendet (MAX_CURSOR_NAME). Ist der Cursorname länger so wurde eine Exception geworfen. Jetzt wird erkannt, dass der Buffer zu klein ist und es wird ein dynamischer Buffer mit ausreichender Größe alloziert und der Name dann abgefragt.
  •  xutility (STL und auch CRT)
    In der Basisklasse der Iteratoren wurde eine Änderung gemacht. Scheinbar hat die Zuweisung eines „leeren/nicht initialisierten“ Iterators bisher einen Iterator gar nicht verändert. Der alte Iterator wurde nicht aufgelöst durch _Orphan_me. Dies bringt dann Probleme mit sich wenn der _ITERATOR_DEBUG_LEVEL mit 2 genutzt wird.
    Da dieser STL Code auch komplett in der CRT verwendet wird, hat dies auch Einfluß auf die CRT.
    Auf die Release Version aber hat diese Code-Änderung jedoch keinen Einfluss, soweit ich das erkennen kann.

Es gibt noch einige andere Dateien, die geändert wurde, aber hier haben sich nur unwichtige Kommentare geändert.

Fazit: Alles in allem ein Sicherheitspatch, der eher Bugfixes enthält, aber selbst die sind nicht sonderlich weitreichend. Und der Nutzerbereich, der mit der ATL den Kernel Transaction Manager nutzt, wird wohl eher klein sein…

PS: Die Dateien dieses Sicherheitspatches haben die Version 10.0.40219.325.
Die Dateien aus dem VS-2010 SP1 haben die Versionsnummer 10.0.30319.1.

Nachtrag 01.12.2011, MSDN Links:
Sicherheits Bullentin:   MS11-025
Knowledge Base-Artikel (KB-Artikel):  KB2565057

LNK2001: unresolved external symbol _mainCRTStartup

Ich habe einige Zeit gebraucht um herauszufinden warum ein Benutzer von VC-Express die folgende Meldung bekam:

1>------ Build started: Project: Hallo Welt, Configuration: Debug Win32 ------
1>LINK : error LNK2001: unresolved external symbol _mainCRTStartup
1>Hallo Welt.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Der User war ein Anfänger und hat ein leeres Win32 Projekt erzeugt. Anschließend eine Sourcedatei und hat das typische „Hello World“ Programm schreiben wollen.
Das Problem war aber, dass er zwar die Sourcedatei angelegt hat, diese aber nicht in das erzeugte Projekt eingefügt hat.
Sobald man über die erzeugte Sourcedatei über den Menüpunkt File -> Move file Hello World.cpp into -> Hello World  in das Projekt einfügt, klappt alles wie erwartet.
Man kann die Datei natürlich auch über das Kontexmenü im Projekt hinzufügen, oder per Drag & Drop auf den Solution Explorer ziehen.

Und eigentlich ist die Meldung auch klar, für den der sie versteht. Der Linker läuft an, findet keine Objektdateien. Entsprechend werden auch keine CRT Libraries einbezogen und geladen. Aber der Linker will gemäß den Einstellungen einen entsprechenden Einsprungpunkt für die CRT finden und wirft die obige Fehlermeldung aus.

Ich muss ehrlich sagen, dass mir die Fehlermeldung erst etwas gesagt hat, als ich per Email, das Beispielprojekt zugesendet bekam.