Как я могу отладить вызов C ++ удалить на Android NDK? - PullRequest
0 голосов
/ 23 марта 2011

У меня есть приложение Android C ++, которое управляется слоем Java.В этом коде я использую старую физическую библиотеку (токамак) и почти ничего не делаю, я создаю и удаляю симулятор следующим образом:

static neSimulator *gSim;
neV3 gravity; gravity.Set(0.0f, -10.f, 0.0f);
neSimulatorSizeInfo sizeInfo;
sizeInfo.rigidBodiesCount = 1;
sizeInfo.animatedBodiesCount = 1;
sizeInfo.geometriesCount = 2;
sizeInfo.overlappedPairsCount = 2;
gSim = neSimulator::CreateSimulator(sizeInfo, NULL, &gravity);

И уничтожаю его:

neSimulator::CreateSimulator(gSim);

Это работает, проблема возникает, когда я начинаю добавлять геометрию:

neV3 ballPos;
rgdBall = gSim->CreateRigidBody();
neGeometry *geoBall = rgdBall->AddGeometry();
geoBall->SetSphereDiameter(1.5f);
rgdBall->UpdateBoundingInfo();
rgdBall->SetMass(2.0f);
rgdBall->SetInertiaTensor(neSphereInertiaTensor(1.5f, 2.0f));
ballPos.Set(0.0f, 5.0f, 0.0f);
rgdBall->SetPos(ballPos);

В этом случае, когда я вызываю команду destroy (и я вызываю ее только один раз), я получаю deadbaad SIGSEGV (Null Pointer).

У меня есть все отладочные операторы журнала для метода деструктора, и код внутри деструктора завершается до конца.Итак, есть этот код:

void neSimulator::DestroySimulator(neSimulator * sim)
{
    __android_log_print(ANDROID_LOG_INFO, "TOKAMAK", "Before cast");
    neFixedTimeStepSimulator * s = reinterpret_cast<neFixedTimeStepSimulator *>(sim);
    __android_log_print(ANDROID_LOG_INFO, "TOKAMAK", "After cast");
    __android_log_print(ANDROID_LOG_INFO, "TOKAMAK", "Before delete");
    delete s;
    __android_log_print(ANDROID_LOG_INFO, "TOKAMAK", "After delete");
}

Итак, я регистрирую деструктор:

neFixedTimeStepSimulator::~neFixedTimeStepSimulator()
{
    FreeAllBodies();

    if (perf)
        delete perf;
        __android_log_print(ANDROID_LOG_INFO, "TOKAMAK", "dtor complete");
}

Что меня беспокоит, так это то, что я вижу сообщение о завершении dtor в журнале, но не после удалениясообщение и ошибка SIGSEGV.

Как мне лучше исследовать это?

[Больше информации после дальнейшего исследования]

Поэтому я использовал инструмент addr2line для исследования трассировки стека ипроследил ошибку к распределителю памяти по умолчанию.Поэтому я добавил запись во все распределенные и бесплатные звонки:

03-23 13:31:14.617: INFO/neAllocatorDefault(326): malloc 0x1b3fd8 size 2292
03-23 13:31:14.617: INFO/neAllocatorDefault(326): malloc 0x1b48d0 size 488
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x44ae3008 size 114404
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1a58b8 size 8
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1b4ac0 size 800
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1b4de8 size 416
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1b4f90 size 836
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1aca10 size 44
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1b52d8 size 2500
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1b5ca0 size 2500
03-23 13:31:14.627: INFO/neAllocatorDefault(326): malloc 0x1b6668 size 2500
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1b7030 size 400
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1b71c8 size 800
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x424ed008 size 72404
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1b74f0 size 4004
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1b8498 size 2044
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1b8c98 size 6044
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1ba438 size 5004
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1bb7c8 size 11204
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1be390 size 340
03-23 13:31:14.637: INFO/neAllocatorDefault(326): malloc 0x1be4e8 size 4000
03-23 13:31:14.647: INFO/neAllocatorDefault(326): malloc 0x1bf490 size 4000
03-23 13:31:14.647: INFO/neAllocatorDefault(326): malloc 0x1c0438 size 38800
03-23 13:31:14.647: INFO/neAllocatorDefault(326): malloc 0x1c9bd0 size 38800

И

03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b71c8
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b7030
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b6668
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b5ca0
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b52d8
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1aca10
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b4f90
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b4de8
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b4ac0
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1a58b8
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x44ae3008
03-23 13:31:19.508: INFO/neAllocatorDefault(326): free 0x1b48d0

Так что SIGSEGV происходит при попытке освободить 0x1b48d0, забавно то, что есть предыдущий mallocкоторый возвратил этот указатель, а предыдущий не был свободен.Я теперь еще больше озадачен ...

Ответы [ 2 ]

0 голосов
/ 31 марта 2011

Нашел проблему. Токамак использует специальный метод распределения, чтобы избежать исключений (я думаю). Для каждого нового экземпляра объекта он делает что-то вроде:

// assume you have a class MyObject
// and the default allocator is the C malloc/free functions:
MyObject *obj = new (malloc(sizeof(MyObject))) MyObject;
... do something with the obj ...
free(obj);

Так что это отлично работает для объекта, проблема с массивами. С массивами код Tokamak делал:

MyObject[] *obj = new (malloc(sizeof(MyObject) * elements + 4)) MyObject[];
... do something with the obj ...
free(obj); // Kaboom!!!

Здесь, похоже, дело в том, что компилятор ndk использует более 4 байтов (32-битное целое) для индексов массивов, если я расширю код до +8, тогда все просто работает.

0 голосов
/ 23 марта 2011

Я подозреваю, что reinterpret_cast в DestroySimulator неверны. Объект, вероятно, удаляется с использованием другого типа, чем он есть на самом деле, что вызывает неверный деструктор, который, в свою очередь, повреждает метаданные распределителя и приводит к сбою free.

При удалении приведенных объектов необходимо соблюдать две важные вещи:

  1. Выбираемый деструктор выбирается на основе статического типа выражения в delete. Таким образом, тип должен совпадать с типом, передаваемым в new, или только если объект имеет виртуальный деструктор, может быть базовым типом типа, передаваемого в new.
  2. Приведение между указателем на производный класс и указателем на его базовый класс не может быть численно эквивалентным. static_cast знает, как настроить указатель, но с помощью reinterpret_cast вы явным образом сообщите компилятору, чтобы он не корректировался, поэтому указатель может быть неправильным (это может произойти, только если задействовано множественное наследование, но это может быть где-то глубоко в библиотеке).

Использование reinterpret_cast в C ++ почти всегда неправильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...