Исключение, вызванное неожиданным кодом ассемблера после вызова новой (кучи)

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

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

Коды С++ выглядят так.

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

А сгенерированный код на ассемблере имеет обработку завершить/удалить/выбросить после вызова new. Похоже, этот шаблон применяется ко всем вызовам 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

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

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

Спасибо


person Martin    schedule 22.12.2010    source источник
comment
Это многопоточный код? Попробуйте проверить использование памяти кода, прежде чем создавать новые броски.   -  person DumbCoder    schedule 22.12.2010
comment
Это однопоточный код. Для меня это выглядит так, как будто new не выполняет бросок, потому что в этом случае я ожидал бы увидеть __builtin_new в стеке вызовов (а вызов ___sjthrow находится на том же уровне стека, что и показанный код). Или это может быть повторный бросок при обработке исключения, созданного конструктором. Я проверю использование памяти в следующем году.   -  person Martin    schedule 23.12.2010


Ответы (2)


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

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

person villintehaspam    schedule 22.12.2010
comment
Неплохо подмечено. Следующим, что нужно искать, может быть повторный бросок исключения. В этом случае я бы не увидел вызов конструктора или вызов new в стеке вызовов. Я проверю это в следующем году. Спасибо - person Martin; 23.12.2010

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

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

Кажется, что в VxWorks вы не видите «новый» вызов функции в трассировке стека в случае возникновения исключения после состояния нехватки памяти.

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

person Martin    schedule 24.02.2011