Parameter - Debugger zeigt <Schlechtes Ptr> - Absturz



  • Hallo,

    Ich habe neben meinem mainThread(1) einen weiteren Thread(2) laufen.
    Thread(2) ruft nun eine Callback Funktion im Thread(1) auf.
    In dieser Callback-Funktion wird eine weitere Funkion mit 3 Parametern aufgerufen.
    Beim Debuggen wird noch in diese Funktion rein gesprungen, aber sobald auf die Parameter zugegriffen wird, stürzt der Debugger ab.
    Fehlermeldung:
    Unbehandelte Ausnahme bei 0x... in xyz.exe. Zugriffsverletzung beim Schreiben an Position 0x....

    Wenn ich im Debugger mit dem Cursor auf einen Parameter gehe, zeigt mir VS <Schlechtes Ptr> an.
    Irgendwie wird nichts übergeben oder was falsches. Woher kommt das? Wie kann ich den Fehler weiter eingrenzen?

    Danke

    Gruß
    Michael



  • Das ist alles zu vage, als dass man da eine Aussage treffen könnte.
    Kannst du ein Minimalbeispiel basteln und den Quelltext hier posten?



  • Wie kann man denn eine Callback in einen anderen Thread machen... bzw. wie hast Du das gemacht?
    Ich vermute, dass der Zeiger eben nicht mehr gültig ist, da das Objekt schon von jemandem anderen zerstört wurde...



  • Okay, ich versuche mal ein Beispiel zu geben.

    Hier ein Ausschnitt des Code aus der main.cpp

    //mainTread
    PeakCan	*myPeakCan;
    #define MAX_FRAME	100
    TCANoverSocketMsg SocketCanFrame[MAX_FRAME];
    WORD SocketCanFrameReadPtr = 0;
    WORD SocketCanFrameWritePtr = 0;
    int main(int argc, char* argv[])
    {
      myPeakCan = new PeakCan());
    myPeakCan->ConnectClient();
      myPeakCan->CanReceiveHandler(onCanReceiveHandler);
    }
    
    void onCanReceiveHandler(TCANRcvMsg RcvMsg)
    {
      switch(RcvMsg.msgbuff.MSGTYPE)
      {
    	case MSGTYPE_STANDARD:
    	 SocketCanFrame[SocketCanFrameWritePtr].ID = RcvMsg.msgbuff.ID;
    
    fprint_long_canframe(stdout,&SocketCanFrame[SocketCanFrameWritePtr],0,CANLIB_VIEW_ASCII); 
    		if(++SocketCanFrameWritePtr > MAX_FRAME-1)
    			SocketCanFrameWritePtr = 0;
    		break;
    		case MSGTYPE_STATUS:
    			break;
    		default:
    			break;
    	}
    }
    

    Hier ein Codeausschnitt aus der PeakCan Klasse wo ein Thread angelegt wird

    //PeakCan Klasse (Thread2)
    ...
    TOnCanReceiveHandler g_fpOnCanReceive = 0;
    
    int PeakCan::ConnectClient (void)
    {
    	DWORD dwGenericThread;
    	ConnectClientToNet();
    	hPeakCanReadThread = CreateThread(NULL, 0, CanRead, myPcanApiDrv, 0, &dwGenericThread);
    	if(hPeakCanReadThread == NULL)
        {
    		DWORD dwError = GetLastError();
    		sprintf_s(sBuf,ERROR_BUF_SIZE,"PEAK_CAN: Error in Creating PeakCanReadThread thread %x\r\n",dwError);
    		DEBUG_PEAK_CAN_OUTPUT(sBuf);
            //cout<<"PeakCan: Error in Creating PeakCanReadThread thread"<<dwError<<endl ;
            return (0);
        }
    	return -1;
    }
    
    DWORD WINAPI PeakCan::CanRead (LPVOID pParam)
    {
    	DWORD retVal;
    	TCANRcvMsg myCanRecMsgBuff;
    	while(1)
    	{
    		((CPcanApiDrv*)pParam)->CANWaitForSingleObject(INFINITE);
    		retVal = ((CPcanApiDrv*)pParam)->CANRead(&myCanRecMsgBuff.msgbuff, &myCanRecMsgBuff.hNet, &myCanRecMsgBuff.rcvtime);
    		if(g_fpOnCanReceive != 0)
    			g_fpOnCanReceive(myCanRecMsgBuff);
    	}
    }
    
    //Tools.cpp
    void fprint_long_canframe(FILE *stream , TCANoverSocketMsg *cf, char *eol, int view) {
    	/* documentation see lib.h */
    	//stream = stdout;
    	char buf[MAX_LONG_CANFRAME_SIZE];
    	sprint_long_canframe(buf, cf, view);
    	fprintf(stream, "%s", buf);
    	if ((view & CANLIB_VIEW_ERROR) && (cf->ID & CAN_ERR_FLAG)) {
    		//snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
    		fprintf(stream, "\n\t%s", buf);
    	}
    	if (eol)
    		fprintf(stream, "%s", eol);
    
    }
    

    So, ich hoffe das es mit den Codeausschnitten besser verständlich ist.

    Gruß
    Michael


  • Mod

    Nö!

    Wo bleibt denn der Debugger stehen?
    Was sagt der Callstack?



  • Der Debugger bleibt in der Funktion fprint_long_canframe in der Tools.cpp in der Zeile

    fprintf(stream, "%s", buf);
    

    stehen. Also wenn man diese Zeile ausführt kommt die Fehlermeldung.
    Im Callstack (Aufrufliste?) steht vor dem Ausführen der Zeile folgendes:

    SocketServerCode.exe!fprint_long_canframe(_iobuf * stream=0xfefefefe, TCANoverSocketMsg * cf=0xfefefefe, char * eol=0xfefefefe, int view=0xfefefefe) Zeile 162 C++
    fefefefe()
    SocketServerCode.exe!PeakCan::CanRead(void * pParam=0x00a27690) Zeile 502 + 0x1a Bytes C++
    kernel32.dll!767633aa()
    [Unten angegebene Rahmen sind möglicherweise nicht korrekt und/oder fehlen, keine Symbole geladen für kernel32.dll]
    ntdll.dll!774a9ef2()

    danach:

    ntdll.dll!774922b2()
    [Unten angegebene Rahmen sind möglicherweise nicht korrekt und/oder fehlen, keine Symbole geladen für ntdll.dll]
    > msvcr90d.dll!_lock_file(_iobuf * pf=0xfefefefe) Zeile 242 C
    msvcr90d.dll!fprintf(_iobuf * str=0xfefefefe, const char * format=0x0085ebbc, ...) Zeile 63 + 0x9 Bytes C
    SocketServerCode.exe!fprint_long_canframe(_iobuf * stream=0xfefefefe, TCANoverSocketMsg * cf=0xfefefefe, char * eol=0xfefefefe, int view=0xfefefefe) Zeile 162 + 0x18 Bytes C++
    fefefefe()
    SocketServerCode.exe!PeakCan::CanRead(void * pParam=0x00a27690) Zeile 502 + 0x1a Bytes C++
    kernel32.dll!767633aa()
    ntdll.dll!774a9ef2()
    ntdll.dll!774a9ec5()



  • Halllo, hab gerade das hier in einem andern Thread gefunden:

    Die Ausnahme weist dich drauf hin, dass irgendwer versucht, über einen Pointer auf Speicher zuzugreifen, der dem Prozess nicht gehört. Deshalb Zugriffsverletzung. Die Adresse, an der er lesen will, hast höchstwahrscheinlich du übergeben. Direkt oder indirekt. Wenn du ein wenig googlest, wirst du rausfinden, dass 0xfefefefe darauf hindetutet, dass es da um freigegebenen Speicher geht, sprich die Funktion sucht sich von "irgendwo" einen Pointer und versucht drauf zuzugreifen. Der Pointer hat aber den Wert 0xfefefefe, liegt also in freigegebenem Speicher. Ich schätze, du hast ihm einen Pointer übergeben, der auf etwas zeigt, das schon längst wieder freigegeben wurde. Ich rate mal ins Blaue: lpExpNew ist so ein Pointer.(Hinweis: delete lpExpNew; gibt den Speicher frei, setzt aber den Pointer nicht auf 0)
    *

    Ich vermute das es auch auf mein Problem zutrifft, verstehe es aber nicht richtg.


  • Mod

    Lass Dein Program im Debugger laufen und das Programm blebt dort stehn wo das Prblem auftritt.
    Ist das so schwer mal auszuprobieren.
    Zudem hast Du noch den Callstack, der Dir auch Infos gibt.

    Ein Zeiger ist ungültig..

    Was ist denn mit myPcanApiDrv? Ist der Zeiger gültig?



  • Das Programm bleibt im File _file.c in der Funktion

    void __cdecl _lock_file (FILE *pf)
    

    in der letzten Zeile stehen.

    Wo finde ich denn den Callstack. Ich habe hier die Reiter Aufrufliste, Haltepunkte, Ausgabe, Fehlerliste, Aufrufbrowser

    Was in der Aufrufliste steht hab ich ja eben gepostet.



  • Michael65589 schrieb:

    Halllo, hab gerade das hier in einem andern Thread gefunden:

    Die Ausnahme weist dich drauf hin, dass irgendwer versucht, über einen Pointer auf Speicher zuzugreifen, der dem Prozess nicht gehört. Deshalb Zugriffsverletzung. Die Adresse, an der er lesen will, hast höchstwahrscheinlich du übergeben. Direkt oder indirekt. Wenn du ein wenig googlest, wirst du rausfinden, dass 0xfefefefe darauf hindetutet, dass es da um freigegebenen Speicher geht, sprich die Funktion sucht sich von "irgendwo" einen Pointer und versucht drauf zuzugreifen. Der Pointer hat aber den Wert 0xfefefefe, liegt also in freigegebenem Speicher. Ich schätze, du hast ihm einen Pointer übergeben, der auf etwas zeigt, das schon längst wieder freigegeben wurde. Ich rate mal ins Blaue: lpExpNew ist so ein Pointer.(Hinweis: delete lpExpNew; gibt den Speicher frei, setzt aber den Pointer nicht auf 0)
    *

    Ich vermute das es auch auf mein Problem zutrifft, verstehe es aber nicht richtg.

    Wenn du einen Zeiger auf einen nichtgültigen Speicherbereich hast, also Speicher, auf den du im Kontext deiner Anwendung nicht zugreifen darfst, dann wird eine Exception ausgelöst, und zwar eine Access Violation Exception.

    Wenn du Speicher mit delete freigibst, dann musst du immernoch den Wert des Pointers auf NULL setzen, da delete das nicht selbst macht.

    short* myPtr;
    ....
    delete myPtr;
    myPtr = NULL;
    


  • Ja, aber wie passt das denn auf mein Problem?

    Ich rufe eine Funktion auf, deren Parameter aus drei Pointern und einer Variablen besteht.
    Wenn ich dann in der Funktion bin und mir die Pointer ansehe, stehen die alle auf 0xfefefefe.
    Also dachte ich das hier dann Speicher benutzt wird der nicht frei gegeben ist, oder was auch immer. Jedenfalls scheint diese 0xfefefefe ja ein Hinweis zu sein.

    Ich versteh jedoch nicht warum es dann ein Speicherproblem gibt. Kann man den Fehler denn nicht besser eingrenzen?



  • Für mich sieht es eher so aus, also ob Du Dir Deinen Stack überschreibst... aktivieren doch mal den PageHeap =>

    gflags /p /enable NameDer.EXE /full



  • Hab neue Erkenntnisse. Hab den Code wie folgt geändert:

    void fprint_long_canframe(FILE *stream , TCANoverSocketMsg *cf, char *eol, int view) {
    	/* documentation see lib.h */
    	//stream = stdout;
    	static FILE* Temp = stream;
    	static TCANoverSocketMsg *cfTemp = cf;
    	static char *willi = eol;
    	static int ierwin = view;
    	char buf[MAX_LONG_CANFRAME_SIZE];
    	sprint_long_canframe(buf, cf, view);
    	fprintf(Temp, "%s", buf);
    	if ((ierwin & CANLIB_VIEW_ERROR) && (cfTemp->ID & CAN_ERR_FLAG)) {
    		//snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
    		fprintf(Temp, "\n\t%s", buf);
    	}
    	if (willi)
    		fprintf(Temp, "%s", willi);
    
    }
    

    Hab also die Parameter zwischengespeichert. Ursprünglich waren die Parameter nach Eintritt in die Funktion okay. Nach Aufruf der Funktion

    sprint_long_canframe(buf, cf, view);
    

    stand in den parametern überall 0xfefefefe.

    Jezt kommt folgende Fehlermeldung wenn ich die Funktion fprint_long_canframe verlasse:

    Run-Time Check Failure #2 - Stack around the variable 'buf' was corrupted.



  • int main(int argc, char* argv[]) 
    { 
      myPeakCan = new PeakCan()); 
    myPeakCan->ConnectClient(); 
      myPeakCan->CanReceiveHandler(onCanReceiveHandler); 
    }
    

    Nur so aus logischer Sicht:

    Sollte eine Callback Funktion nicht vor einer bewirkenden Methode registriert werden? Immerhin wird ein Thread erstellt, welcher auch irgendwann deine Callback Func aufruft. Könnte zu undefiniertem Verhalten führen. Das solltest du ändern.



  • Woher weis die Funktion "sprint_long_canframe" wieviel sie maximal in "buf" schreiben darf? AUch würde ich große Datenmengen nie auf dem Stack anlegen sondern immer auf dem Heap.

    Leg es auf den Heap (malloc), dann FullPageHeap aktivieren, dann siehst Du sofort wo es kracht...



  • Die max länge für buf ist über ein Define im Header angegeben. Beschrieben wird buf über sprintf_s und dort gebe ich das define als max-länge mit.

    Wie benutzt man FullPageHeap? Hab ich noch nie von gehört.

    Hab gerade buf mal mit malloc angelegt. Jezt werden auch die Paramter nicht mehr verbogen. Es hat also definitiv etwas mit dem Stack zu tun.

    Die Funktion sieht jetzt so aus:

    void fprint_long_canframe(FILE *stream , TCANoverSocketMsg *cf, char *eol, int view) {
    	/* documentation see lib.h */
    
    	char *buf = (char*)malloc(MAX_LONG_CANFRAME_SIZE);//[MAX_LONG_CANFRAME_SIZE];
    	sprint_long_canframe(buf, cf, view);
    	fprintf(stdout, "%s", buf);
    	if ((view & CANLIB_VIEW_ERROR) && (cf->ID & CAN_ERR_FLAG)) {
    		//snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
    		fprintf(stdout, "\n\t%s", buf);
    	}
    	if (eol)
    		fprintf(stdout, "%s", eol);
    
    	free(buf);
    }
    

    Wenn ich allerdings jetzt die Funktion verlassen, kommt folgende Fehlermeldung:

    Windows hat einen Haltepunkt in xyz.exe ausgelöst.
    Dies kann auf eine Beschädigung des heaps zurückzuführen sein, die auf eine Problem in xyz.exe oder in einer der geladenen DLLs hinweist.



  • Ich habe das Programm gflags.exe auf meinem Rechner. Da kann man "Enable page heap" aktivieren.



  • Wie Du ja auch erkennen kannst, wird eben der Puffer überschrieben!!! Stelle also sicher, dass Du wirklich genügend Speicher allokiert hast und an beiden Stellen das *gleiche* Define verwendest! Besser noch: Übergebe die Länge!!!



  • Full PageHeap:

    gflags /p /enable NameDer.EXE /full

    Musst allerdings als "Admin (UAC)" ausführen!



  • Hi Jochen,
    wird dann Full PageHeap nur für die EXE aktiviert? Ich hatte es über gflags.exe aktiviert (anscheinend global) und nach einem Neustart war der Rechner grotten langsam. Hab es jetzt über gflags.exe wieder raus genommen.

    Wenn ich das aktiviert habe, starte ich ganz normal den debugger und lasse das Programm laufen bis es abstürzt. Und dann? Sollte der Debugger mir jetzt etwas spezielles anzeigen, oder wird irgendwo eine Datei angelegt?

    Danke noch mal für Eure Mühe und Gedult.


Anmelden zum Antworten