2010-12-22 12 views
3

Ich jage eine Ausnahme, die von einem Teil des Codes, der vom Compiler nach jedem Aufruf an neue hinzugefügt wird geworfen wird. Es ist der Standard C++ neue, die etwas Speicher vom Heap erhalten und den Konstruktor der Klasse aufrufen sollte.Ausnahme von unerwartetem Assembler-Code nach einem Aufruf von new (Heap)

Wir betreiben VxWorks 5.5.1 mit GCC 2.95 (oder 2.96 nicht sicher) auf einem SH4-Prozessor. Kompiliert in SNiFF + 4.1 Patch 1.

Der C++ - Code sieht so aus.

CBlocksFile* pBlockFile = new CBlocksFile(szHeaderFile, szDataFile); 

und der erzeugte Assembler-Code hat eine beenden/löschen/ Handhabung nach dem Aufruf neuen werfen. Dieses Muster scheint auf alle Anrufe an neue angewendet werden.

// call to "new" 
c4d6000 d14d  mov.l  @(0x134,pc),r1 (= 0x0c06c1e0 = ___builtin_new) 
c4d6002 410b  jsr  @r1 
c4d6004 e414  (mov  #20,r4) 
... 
// compiler generates throw path address 
c4d6022 d246  mov.l  @(0x118,pc),r2 (= 0x0c4d6034) 
... 
// and pushes it to the stack 
c4d602c 1121  mov.l  r2,@(4,r1) 
... 
c4d6030 a002  bra  +4  (==> 0x0c4d6038 : GOOD_PATH) 
... 
// throw path (there is no visible jump to this address) 
c4d6034 a088  bra  +272  (==> 0x0c4d6148 : THROW_PATH) 
... 
GOOD_PATH: 
... 
// call to constructor 
c4d6058 d139  mov.l  @(0xe4,pc),r1 (= 0x0c4d1730 T ___Q211CBlocksFilePCcT1bUcl) 
... 
c4d6060 410b  jsr  @r1 
... 
// normal path 
return 

THROW_PATH: 
... 
// same pattern again, compiler generates terminate path address 
c4d6164 d22f  mov.l  @(0xbc,pc),r2 (= 0x0c4d6172) 
... 
// and pushes it to the stack 
c4d616a 1121  mov.l  r2,@(4,r1) 
... 
c4d616e a002  bra  +4  (==> 0x0c4d6176 : NO_TERMINATE) 
... 
c4d6172 a039  bra  +114  (==> 0x0c4d61e8 : TERMINATE_A) 
... 
NO_TERMINATE: 
... 
// delete handling 
if (??) 
c4d617c 2118  tst  r1,r1 
c4d617e 8d04  bt/s  +8  (==> 0x0c4d618a) 
... 
{ 
    delete ?? 
... 
c4d6184 d128  mov.l  @(0xa0,pc),r1 (= 0x0c06be20 = ___builtin_delete) 
c4d6186 410b  jsr  @r1 
... 
} 
c4d618a 9044  mov.w  @(0x88,pc),r0 (= 0x0000028c) 
c4d618c 02ee  mov.l  @(r0,r14),r2 
c4d618e 5121  mov.l  @(4,r2),r1 
c4d6190 6112  mov.l  @r1,r1 
c4d6192 1211  mov.l  r1,@(4,r2) 
c4d6194 d125  mov.l  @(0x94,pc),r1 (= 0x0c06a880 = ___sjthrow) 
c4d6196 410b  jsr  @r1 

Wofür ist dieser Code nützlich? Es sieht nicht so aus wie die Bedingung "kein Speicher", da der Wurf nicht innerhalb der neuen Funktion liegt.

Warum wird der Wurf genannt? Und von wem? Es gibt das doppelte Muster, eine Codeadresse auf den Stack zu setzen, die später zur Ausführung verwendet werden kann.

Dank

+0

Ist es Multi-Thread-Code? Überprüfe die Verwendung des Code-Speichers vor neuen Würfen. – DumbCoder

+0

Es ist Single-Thread-Code. Für mich sieht es so aus, als würde new den Wurf nicht machen, weil ich in diesem Fall erwarten würde, __builtin_new auf dem Call-Stack zu sehen (und der Aufruf von ___sjthrow ist auf der gleichen Stack-Ebene wie der gezeigte Code). Oder es könnte ein erneuter Wurf sein, wenn eine Ausnahme behandelt wird, die vom Konstruktor ausgelöst wurde. Ich werde die Speichernutzung nächstes Jahr überprüfen. – Martin

Antwort

2

Eine Vermutung wäre, dass dieses Muster angewandt wird, weil es eine Anforderung von C++, dass, wenn der Konstruktor wirft, sollte der Speicher für das Objekt befreit werden. Wenn also eine Ausnahme innerhalb des Konstruktors ausgelöst wird, wird das neu zugewiesene Objekt gelöscht.

Sie könnten immer versuchen, explizit etwas aus dem Konstruktor Ihres Objekts zu werfen, um zu sehen, welche Pfadausführung benötigt wird, um zu überprüfen, ob diese Antwort nützlich ist oder nicht.

+0

Das ist ein guter Punkt. Ein erneuter Wurf der Ausnahme könnte das nächste sein, wonach gesucht werden muss. In diesem Fall würde ich den Aufruf des Konstruktors oder den Aufruf des neuen Aufrufs nicht sehen. Ich werde das nächstes Jahr überprüfen. Vielen Dank – Martin

0

Ich möchte eine schnelle Antwort auf meine eigene Frage geben, nachdem das Problem gelöst ist.

Ich habe einen neuen Fehlerhandler hinzugefügt, um zu sehen, ob es aufgerufen würde. Und es wurde aufgerufen, bevor die erwähnte Ausnahme ausgelöst worden wäre. Also wurde es zu einem "out of memory condition" und innerhalb weniger Stunden habe ich den Speicherleck gefunden.

Es scheint, dass Sie in VxWorks den 'neuen' Funktionsaufruf im Stack-Trace nicht sehen, wenn eine Ausnahme nach einem Speichermangel auftritt.

Dank DumpCoder und Villintechasp haben sie mich in die richtige Richtung denken lassen.