R6025 - pure virtual function call
-
Hallo zusammen,
für unser Werk in China haben wir einen Messautomaten gebaut und vor der Lieferung mehr als eine Woche mit unterschiedlichen Stücken gestestet. Die Maschine lief einwandfrei.
Nach der Inbetriebnahme in China kommt nun nach jeweils ca. 4 Stunden messen die Meldung "Runtime Error! Program: D:\Micro Crystal\UniMeasure\UniMeasure.exe R6025 - pure virtual function call"
Ich habe darauf eine UniMeasure.exe mit aktiviertem MiniDump geschickt, aber leider wird scheinbar bei diesem Fehler kein MiniDump erzeugt.
Bei mir läuft das Programm nach wie vor einwandfrei!
- Was kann diesen Fehler auslösen?
- Wie könnte ich den Fehler reproduzieren um den MiniDump zu testen.
- Irgend einen Hinweis wie ich das Problem lösen könnteGruss
Wale
-
ich habe was gefunden:
set_purecall_handler (handler);
Ich habe das mal im MiniDump modul eingebaut.
Mal schauen ob ich einen brauchbaren MiniDump erhalte.
Gruss
Wale
-
Das Problem taucht auf, wenn du in der Basisklasse eine virtuelle Funktion aufrufst:
class BaseClass { public: BaseClass() { func(); } virtual void func() = 0; }; class DerivedClass : public BaseClass { public: DerivedClass() { } void func() { // do something } }; int main() { DerivedClass dc; }
Der Compiler schluckt das ohne Probleme, während der Laufzeit tritt aber folgendes Problem auf: Der Konstruktor von
DerivedClass
ruft den Konstruktor vonBaseClass
auf. Der Konstruktor ruft die virtuelle Methodefunc
auf, die inDerivedClass
implementiert ist. Da zum Zeitpunkt des Konstruktoraufrufs vonBaseClass
dasDerivedClass
Objekt noch nicht vollständig konstruiert ist kommt es zu der pure-virtual-function-call Fehlermeldung.
-
DocShoe schrieb:
...
Genau.
In der Praxis bei
class BaseClass { public: BaseClass() { globalThingyRegisterMe(this);//wiederum ruft verfrüht this->func() auf } virtual void func() = 0; };
-
Hallo DocShoe und Volkard,
danke für die Beiträge aber...
Ich habe beim Design unserer Maschinenbibliothek peinlichst darauf geachtet, dass solche Dinge nicht vorkommen. Die Bibliothek ist jetzt 10 Jahre alt und wurde immer gepflegt und es laufen zig Programme basierend auf dieser Lib in unseren Werken absolut problemlos. Auch das Programm "UniMeasure" läuft sonst auf über 200 Maschinen und Handmessplätzen einwandfrei.
Wir hatten diese Fehlermeldung bisher auch nur 2 mal. Das erste mal war's ein Bug in einem PCI Karten Treiber und das 2. mal ein falscher Drucker Treiber.
Da aber jetzt mein eigener "pure_call" Handler nicht aufgerufen wird und immer noch die Original Fehlermeldung kommt zweifle ich langsam daran, dass dieser Fehler durch unseren Code ausgelöst wird.
Ich baue aber jetzt mal so einen Fehler wie ihr beschrieben habt in das Programm ein und schaue ob dann mein "pure call" Handler aufgerufen wird.
Ich halte euch auf dem laufenden.
Herzliche Grüsse
Walter
-
Hallo DocShoe,
dein Beispiel kompiliert aber es Linkt nicht
1>Machine.obj : error LNK2019: unresolved external symbol "public: virtual void __thiscall MC::BaseClass::func(void)" (?func@BaseClass@MC@@UAEXXZ) referenced in function "public: __thiscall MC::BaseClass::BaseClass(void)" (??0BaseClass@MC@@QAE@XZ)
Herzliche Grüsse
Walter
-
weicher schrieb:
dein Beispiel kompiliert aber es Linkt nicht
Schlauer Compiler! Aber irgendwie wird es schon gelingen, ihn zu veralbern. Den gcc kriege ich mit:
template<typename T> void foo(T* t){ t->func(); } class BaseClass { public: BaseClass() { foo(this); } virtual void func() = 0; }; class DerivedClass : public BaseClass { public: DerivedClass() { } void func() { // do something } }; int main() { DerivedClass dc; }
oder
class BaseClass { public: BaseClass() { crash(); } void crash() { func(); } virtual void func() = 0; }; class DerivedClass : public BaseClass { public: void func() { // do something } }; int main() { DerivedClass dc; }
edit: und noch ein ganz häßlicher
class BaseClass { public: BaseClass() { } virtual ~BaseClass() { } virtual void func() = 0; }; class DerivedClass : public BaseClass { public: void func() { } }; BaseClass* test() { DerivedClass d[1]; return d; } int main() { BaseClass* b=test(); b->func(); }
-
Hallo Volkard,
mit Deinem 2. Beispiel konnte ich das VS2008 überlisten.
(VS 2008 wegen alter Lib)Auch mein pure_call handler wird getriggert aber es schreibt ein File mit Länge 0
//----- MCPureCallHandler ---------------------------------------------------------- void MCPureCallHandler () { WriteDump (NULL); FatalAppExit (0, "Application failed! MiniDump written"); } //----- WriteDump ------------------------------------------------------------------ bool WriteDump (EXCEPTION_POINTERS* info) { DWORD lastErr = 0; bool bFailed = true; CString str; SYSTEMTIME time; ::GetLocalTime (&time); str.Format (".%04d%02d%02d%02d%02d%02d%03d", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds); TCHAR dumpFile[1024]; GetModuleFileName (NULL, dumpFile, sizeof (dumpFile) / sizeof (TCHAR)); strcat_s (dumpFile, 1024, str); strcat_s (dumpFile, 1024, ".dmp"); ++dmpIdx; HANDLE df = CreateFile (dumpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (df != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION expi; expi.ThreadId = GetCurrentThreadId (); expi.ClientPointers = TRUE; expi.ExceptionPointers = info; HANDLE proc = GetCurrentProcess (); DWORD procID = GetCurrentProcessId (); if (pMDWD (proc, procID, df, dumpTyp, &expi, NULL, NULL)) bFailed = false; else { lastErr = GetLastError (); } CloseHandle (df); } return bFailed; }
proc ist 0xffffffff (ist mit Sicherheit nicht korrekt, Edit: bin mir da nicht mehr so sicher
)
procID ist 3080
lastErr ist "Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
Hast Du irgend eine Idee?
Herzliche Grüsse
Walter
-
ich hab's geschafft
void MCPureCallHandler () { AfxThrowMemoryException (); }
So wird ein MiniDump geschrieben und beim Debuggen die Fehlerhafte Zeile angezeigt.
Es ist wahrscheinlich egal welche Exception man wirft.
Gruss
Walter
-
Bin nur ein wenig verwirrt, daß Du, ohne Exceptioninformationen zu haben, welche setzen willst.
if (pMDWD (proc, procID, df, dumpTyp, &expi, NULL, NULL))
dachte da eher an
if (pMDWD (proc, procID, df, dumpTyp, NULL, NULL, NULL))Deine Lösung, irgendeine Exception zu erzeugen, ist aber auch ganz unterhaltsam.
-
Hallo Volkard,
pMDWD (proc, procID, df, dumpTyp, NULL, NULL, NULL)
hat zwar einen MemoryDump erzeugt aber leider nur code der runtime angezeigt.
Herzliche Grüsse und Danke für die Unterstützung
Walter
-
Gute Nachrichten aus China:
Die neueste Programmversion ist das erste Mal fehlerfrei eine Schicht gelaufen.
Die wahrscheinliche Fehlerursache:
Da UniMeasure schon sehr lange eingesetzt wird, laufen die meisten Maschinen mit dem NI-GPIB Treiber vom July 2000.Bei neuen Maschinen installieren wir manchmal den neuesten NI-GPIB Treiber und haben auch eine Konfiguration um UniMeasure gegen den neuen Treiber zu linken.
Beim generieren der englischen Version von UniMeasure habe ich, völlig überzeugt davon, dass auf der Maschine die alten Treiber installiert sind auch die alte Programmversion geliefert.
Gestern abend wurde ich dann unsicher und habe einen Screenshot von der Maschine verlangt... Es ist eindeutig der neueste GPIB Treiber installiert.
Darauf habe ich die neue Programmversion ausgeliefert was scheinbar geholfen hat.
Herzliche Grüsse
Walter
-
Ich hatte mich zu früh gefreut, die Original Messagebox mit dem "pure virtual call function" kommt immer noch.
Seit dem 13.01.2014 habe ich das UniMeasure im Dauermessen laufen lassen. Heute kurz nach dem Mittag kam dann auch bei mir die Original Messagebox mit dem "pure virtual call function".
Attach to Process... Der Fehler wurde durch die NI4882.dll produziert und da hat scheinbar _set_purecall_handler () keine Wirkung.
Jetzt ist mir auch klar, warum der Fehler nur auf der neuen Maschine in China auftritt und auf der alten (auch in China) nicht.
Wir deinstallieren jetzt mal den neuen Treiber und installieren den vom July2000.
Herzliche Grüsse
Walter
-
*(int*)(0)=0;
-
Hallo Martin
*(int*)(0)=0;
Wenn sowas in meinem Code stehen würde, dann würde mein purecall_handler zuschlagen und einen MiniDump machen.
Macht er aber in meinem speziellen Fall nicht, es kommt der Original "pure function call" Handler.
Attach to Process... Der Fehler wurde durch die NI4882.dll produziert und da hat scheinbar _set_purecall_handler () keine Wirkung.
Der Hinweis auf die NI4882.dll stand genau über dem Hinweis, dass alles weiter unten im Callstack wahrscheinlich ungültig sei. Abgesehen davon dass unterhalb dieses Hinweises nur kryptische Bezeichner standen welche definitv nicht von mir sind.
Die NI4882.dll ist das Interface zum eingekauften NI-GPIB Driver, da habe ich keinen Source.
Schon beim 1.Versuch mit dem neuen GPIB Treiber kam mir komisch vor, dass ich das Autopolling einschalten musste um einen Interrupt beim Service Request des Zählers zu erhalten. Beim alten Treiber musste ich dieses Autopolling nie einschalten.
Gestern Abend habe ich dann noch bemerkt, dass die Messzeit für einen Quarz mit dem alten Treiber bei ca. 300mSec und mit dem neuen Treiber bei ca. 400mSec liegt.
Aktuell läuft die Maschine in China mit dem alten Treiber problemlos. Aber ich will nichts verschreien... warten wir mal die nächste Woche ab.
Herzliche Grüsse
Walter
-
Hallo zusammen,
habe Heute die Bestätigung aus China erhalten:
Beide Maschinen laufen mit der Version vom 16.01.14 mit dem NI-Treiber (July2000) seit dem 16.01.14 ohne Probleme :).
Herzliche Grüsse
Walter