Исключение, выданное неожиданным ассемблерным кодом после вызова new (куча) - PullRequest
3 голосов
/ 22 декабря 2010

Я гоняюсь за исключением, которое выдается из части кода, которая добавляется компилятором после каждого вызова new .Это стандартный C ++ new , который должен получить некоторую память из кучи и вызвать конструктор класса.

Мы запускаем VxWorks 5.5.1 с GCC 2.95 (или 2.96 не уверены вчто) на процессоре SH4.Скомпилировано в SNiFF + 4.1 Patch 1.

Коды C ++ выглядят следующим образом.

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

И сгенерированный ассемблерный код имеет обработку terminate / delete / throw послепозвоните на новый .Кажется, этот шаблон применяется ко всем вызовам new .

// 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

Для чего этот код полезен? Это не похоже на условие отсутствия памяти, потому что бросок не в новой функции.

Почему бросок вызывается?И от кого? Существует двойной шаблон размещения адреса кода в стеке, который может быть использован для последующего выполнения.

Спасибо

Ответы [ 2 ]

2 голосов
/ 22 декабря 2010

Предполагается, что этот шаблон применяется, потому что для c ++ требуется, чтобы в случае сброса конструктора память для объекта была освобождена. Поэтому, если исключение выдается из конструктора, вновь выделенный объект удаляется.

Вы всегда можете попытаться явно сгенерировать что-то из конструктора вашего объекта, чтобы увидеть, какой путь выполняется для проверки, полезен ли этот ответ.

0 голосов
/ 24 февраля 2011

Я хочу дать быстрый ответ на свой вопрос после того, как проблема будет решена.

Я добавил новый обработчик ошибок, чтобы посмотреть, будет ли он вызываться. И он был вызван как раз перед тем, как упомянутое исключение было бы брошено. Так что это превратилось в «нехватку памяти», и через несколько часов я обнаружил утечку памяти.

Похоже, что в VxWorks вы не видите вызов функции 'new' в трассировке стека в случае исключения, возникшего после нехватки памяти.

Благодаря DumpCoder и villintehaspam они заставили меня задуматься о правильном направлении.

...