Ooooh fucking Fuck
Meine Debug-Builds enthalten einen Leak-Detector, der pro Leak einen Call Stack samt Quelldateinamen ausgibt. Er hält sich an die Visual Studio-Standards – ich kann dann einfach ins Ausgabefenster doppelklicken, und das bringt mich zu dem Quelltext, der mit dem Speicherleck zu tun hatte.
Das lief zehn Jahre, aber irgendwann in den letzten Monaten hat das aufgehört, zu funktionieren. Erst sporadisch, dann komplett.
Ich habe eben vier Stunden gesucht und finde den Fehler nicht. Ich habe aber
ganz geile Dinge gelernt, for fucks sake.
Aaaalso. Microsoft verteilt eine
DbgHelp.dll mit der Debug-Help-API. Falls ihr irgendein Programm debuggen wollt, ruft ihr
SymInitialize() auf und habt dann so tolle Funktionen wie
SymFromAddress() (gib mir zu einer Adresse den Namen der Funktion/Variable, die dort liegt) und
SymGetLineFromAddress() (gib mir zu der Adresse einer Funktion/Variable die Quelldatei und Zeile).
Das funktioniert natürlich nur, falls ihr auch die PDB-Dateien dazu habt. Aber ein Symbol Server ist integriert; ihr könnt sie also für Windows-Code on-the-fly von den Microsoft Symbol Servers beziehen und für eigene Programme kompiliert ihr sowieso immer mit PDB.
So weit die Theorie. Die Praxis ist ein Debakel.
Die API ist eine Karikatur aus 16-Bit-ANSI-Code, der durch ein Sammelsurium aus
#defines und Typen wie
DWORD64 irgendwie in die 64-Bit-Ära gehievt wurde. Die komplette Bibliothek ist single-threaded und verlangt, dass ihr selber darauf achtet, sie nie aus zwei Threads zugleich zu nutzen. Die Dokumentation ist voller Blüten wie
Parameter: hProcess
A handle that identifies the caller. This value should be unique and nonzero, but need not be a process handle. However, if you do use a process handle, be sure to use the correct handle. […]
Sowas hat mich noch nie abgeschreckt; ich wrappe sowas weg und nutze die Vorteile.
Dann kam Visual Studio 2017. Weil 75 % der Linker-Zeit für das Schreiben der Debug-Informationen draufgingen,
haben sie FASTLINK eingeführt. Damit wird der Linker viel schneller, aber es ist ein Breaking Change im Dateiformat.
Ihr ahnt, was jetzt kommt.
Die
DbgHelp.dll, die mit Windows kommt, kann das neue Dateiformat nicht. Sie verweigert den Dienst oder crasht den Prozess(!). Sie haben
FASTLINK als Standard eingeführt; überall hat also die Debug-Help-API mit Visual Studio also aufgehört, ordentlich zu funktionieren. Oh fucking Fuckers. For fucks sake fire them all.
Die „Lösung“ ist, dass man die Debugging Tools for Windows installiert und deren
DbgHelp.dll nutzt. Nun kann man die Debugging Tools aber nicht einfach irgendwo runterladen. Man bekommt sie als Teil des Windows-SDKs oder des Driver Development Kits. WARUM KEIN SCHEIß WINDOWS-UPDATE?!
Weil Windows dann nicht weiß, welche
DbgHelp.dll die richtige ist, müsst ihr die DLL (und alle ihre Abhängigkeiten, because FUCK YOU) in das Verzeichnis kopieren, in dem man seine Anwendung debuggt. Ehrlich:
https://docs.microsoft.com/en-us/window ... p-versions
Aber wartet! Irgendwann letztes Jahr haben sie sich gedacht: Lass uns doch mal den Pfad ändern! Die Dokumentation schwafelt von
Program Files\Debugging Tools for Windows, aber
in Wirklichkeit liegt die Grütze nun unter
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\srcsrv. WEIL DAS JA KLAR IST.
Und dann sollte alles funktionieren. Tut es aber nicht; alle meine Aufrufe geben
ERROR_INVALID_ADDRESS zurück. Und ich bin verdammt nochmal
nicht der einzige. Entweder gibt es keine Lösung, oder jeder findet eine andere, immer skurrilere.
Das ist so ein typischer Fall von
you can’t just XXX.
Nein, man kann nicht einfach eine PDB laden und einen Wert daraus abfragen.
Nein, man kann nicht einfach eine DLL benutzen, die Windows beiliegt.
Nein, man kann nicht einfach die Debugging Tools for Windows herunterladen.
Nein, man kann nicht einfach ganz am Anfang der Dokumentation nachlesen, dass die Scheiße sowieso nicht funktioniert und die Benutzung so angenehm ist wie das Lecken von Busfahrerärschen.
Oh wartet! Es gibt noch eine zweite API. Die DIA-API erlaubt, PDBs zu laden und Daten daraus zu lesen. Und jetzt ratet mal, wie man die benutzt …
Na, ganz klar: Jedes Mal, wenn eine neue Visual Studio-Version rauskommt, ändern sich Name der DLL und UID der Schnittstelle. Auszug aus dem Sizer von Aras Pranckevicius und Fabian
ryg Giesen:
Code: Alles auswählen
static const struct DLLDesc
{
const char *Filename;
IID UseCLSID;
} DLLs[] = {
"msdia71.dll", __uuidof(DiaSource71),
"msdia80.dll", __uuidof(DiaSource80),
"msdia90.dll", __uuidof(DiaSource90),
"msdia100.dll", __uuidof(DiaSource100),
"msdia110.dll", __uuidof(DiaSource110),
"msdia120.dll", __uuidof(DiaSource120),
"msdia140.dll", __uuidof(DiaSource140),
// add more here as new versions appear (as long as they're backwards-compatible)
0
};
Oh, das ist ja GANZ GENAU die Art von Code, die ich in meinem Projekt warten möchte. WER HAT DEN LEUTEN, DIE DIESE DEBUGGING-APIS MACHEN, EIGENTLICH INS HIRN GESCHISSEN?!
Wie macht Visual Studio das eigentlich?! Bei WinDbg weiß ich, dass es ebenfalls Debug Help benutzt und deshalb mit
FASTLINK-Programmen ständig abstürzt oder nichts anzeigt. Aber Visual Studio?! Oh ich will’s wahrscheinlich gar nicht wissen.
Ich möchte echt nur einen Call Stack nach Text mit Zeilennummern konvertieren, und jetzt bin ich kurz vor’m Nervenzusammenbruch.
Nachtrag: BWAHAHAHA fuck my life
Wenn in der EXE ein absoluter Pfad zur PDB steht, wie
C:\Users\Krishty\fuck_this_shit.pdb, dann funktioniert es. Wenn einfach nur
fuck_this_shit.pdb drin steht, schlägt es fehl, obwohl alles im selben Verzeichnis liegt.
Oh, und Visual Studio zeigt gar nicht
alle Compiler-Optionen an, wenn ihr in den Projektoptionen auf
Command Line geht. Vererbte Optionen werden teilweise versteckt, sonst hätte ich das im Vergleich mit einem funktionierenden Projekt schon viel früher gefunden. Nein nein, weil die Schwanzköppe da wahllos Parameter ein- und ausblenden, musste ich Executables diffen wie in der Steinzeit. Fuck em, das gibt einen Bug Report.
Nachtrag 2: Bug Report für den UI-Schrott:
https://developercommunity.visualstudio ... rojec.html