2014-01-13 4 views
12

Wir verwenden System.Reflection.Emit, um Code zur Laufzeit aus Quellcode zu generieren (ja - wie in einem Compiler). Wir stellen dem ILGenerator mit MarkSequencePoint usw. korrekte Symbolinformationen zur Verfügung und aktivieren alle Debug-Flags im AssemblyBuilder. Die Assembly wird im selben Prozess im Speicher gehalten, der sie kompiliert hat und direkt ausgeführt wird. Wenn der Debugger von Visual Studio verwendet wird, um die Quelle für den dynamisch generierten Code zu durchlaufen, funktioniert er tatsächlich perfekt, und Visual Studio scheint zu wissen, woher Code in Bezug auf Dateien und Zeilennummern kommt.Falscher Dateipfad und Zeilennummer in Exception-Stack-Traces aus dynamischem Code

JEDOCH - Wenn Ausnahmen vom generierten Code geworfen werden, enthalten die System.Exception Objekte Stack-Traces, die völlig falsch sind. Sie verweisen auf andere (gültige, aber falsche) Dateien und Zeilennummern. Es ruft den Namen der Klasse und der Methode ab, aber die angegebene Datei- und Zeilennummer hat nichts mit dem Codepfad zu tun, von dem die Ausnahme tatsächlich stammt.

Die Dateien, auf die gezeigt wird, sind so unabhängig, dass sie nicht mit Inlining oder Optimierungen verknüpft werden können. Das einzige Muster, das ich erkennen kann, ist, dass es scheinbar von einigen Dateien versetzt wird (in einer imaginären alphabetisch sortierten Liste von Quelldateien, aus denen die Assembly gebaut wurde). Dieses Muster ist jedoch nicht zu 100% konsistent, und es erscheint irrational, dass dies mit der Ursache des Problems verknüpft ist.

Wenn ich ein System.Diagnostics.Debug-Objekt aus der Ausnahme erstellen, enthält es die gleichen fehlerhaften Informationen.

Ich nehme an, dass die .NET-Laufzeit die gleichen Metadaten verwendet, um Exception Stack-Traces zu erstellen, wie der Debugger zum Durchlaufen des Codes verwendet. In diesem Fall ist dieses Verhalten wirklich seltsam.

Ich versuche herauszufinden, ob dies ein bekannter Fehler in .NET ist, wenn es um dynamische In-Memory-Assemblies geht, oder wenn jemand ähnliche Probleme in anderen Bereichen gesehen hat.

+5

Sie könnten ein kleines und vollständiges Programm veröffentlichen, das wir testen könnten?Sie könnten zum Beispiel eine "Sprache" aus zwei Zeilen oder so programmieren, dass Sie keinen vollständigen Compiler schreiben müssten. –

+1

Kompilieren Sie mit der 'optimize' Flagge? – Andrew

+0

Andrew: Auf dem Compiler oder auf dem Assemblybuilder? Ich habe versucht, so viele "Ja, ich möchte so viele Debug-Informationen wie möglich" Flags wie möglich zu setzen, aber ich bin mir vielleicht nicht alle bewusst. – Duckers

Antwort

1

Okay, ich war NICHT in der Lage, herauszufinden, was das Problem verursacht und wie .NET sich korrekt verhält, aber zumindest konnte ich einen Workaround finden, der auch für andere funktioniert, die das gleiche Problem haben.

  1. Als ich die CIL-Bytecode bin Erzeugung Ich bin der Aufbau eine separate Datenbank, die Methodennamen abbildet (vollständiger Pfad) und IL-Offset zurück zu den ursprünglichen Dateinamen und Zeilennummern.

  2. Wenn Ausnahmen abgefangen werden, untersuche ich den Stack-Trace und verwende nur die GetMethod() und GetILOffset() Informationen von den Stack-Frame-Objekten. Diese Information von der CLR ist korrekt, auch wenn GetFileName() und GetFileLineNumber() falsch sind.

  3. Dann verwende ich für jeden Stack-Frame den Methodenname und IL-Offset, der von der Exception abgerufen wurde, um in meiner generierten Datenbank nach dem tatsächlichen Dateinamen und der Zeilennummer für jeden Stack-Frame zu suchen.

  4. Die Frames, über die ich keine Informationen in der Datenbank finde, sind normalerweise Stack-Frames in vorkompilierten .NET-Modulen, für die die aus CLR abgerufenen Informationen tatsächlich korrekt sind. Für diese Frames verwende ich GetFileName() und GetFileLineNumber() direkt auf dem Stack-Frame.

Verwandte Themen