我如何调试Android NDK上的C++删除调用?

问题描述:

我有一个由Java层管理的Android C++应用程序。在这段代码中我使用的是旧的物理库(托卡马克),我几乎做了什么,我创建和删除这样的模拟器:我如何调试Android NDK上的C++删除调用?

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(我只调用一次),我收到了SIGSEGV(空指针)deadbaad:当我开始添加几何出现问题。

我已经将所有的日志语句调试到析构函数方法中,析构函数中的代码完成到最后。所以有这样的代码:

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"); 
} 

什么是搞乱我的是,我看到在日志中的析构函数完整的消息,但不删除消息和SIGSEGV后错误。

如何更好地调查它?

[经进一步调查后更多信息]

所以我用了addr2line工具来调查堆栈跟踪和追踪误差为默认的内存分配器。所以我加了登录到所有alloc和免费电话:

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并没有以前的免费。我现在更加困惑...

我怀疑reinterpret_castDestroySimulator是错的。该对象可能使用与实际不同的类型进行删除,这会调用错误的析构函数,从而损害分配程序元数据并导致free崩溃。

有删除铸造对象时观察到两个重要的事情:

  1. 被称为析构函数是基于delete静态型表达的选择。因此,类型必须与传递给new的类型相同,或者仅当该对象具有虚拟析构函数时,才可以是传递给new的类型的基本类型。
  2. 在指向派生类的指针和指向它的基类的指针之间进行Casting可能在数值上不等效。 static_cast知道如何调整指针,但通过使用reinterpret_cast您明确告诉编译器不要调整它,所以指针可能是错误的(它应该只发生在涉及多个继承的情况下,但它可能位于库中的某处)。

在C++中使用reinterpret_cast几乎总是错的。

+0

否reinterpret_cast是正确的,因为这两种类型是相关的,lib返回的是neFixedTimeStepSimulator的子类。做一些验证测试显示两个对象的完整性是正确的。 – 2011-03-23 16:23:59

+0

@Paulo:如果它是一个子类,'reinterpret_cast'尤其不正确。如果这些类型是相关的,你应该至少使用'static_cast'。事实上,如果它返回声明类型的子类,它可能是多态的(具有虚拟方法,否则这将是无用的事情),您可以使用'dynamic_cast'在运行时检查该对象的确是给定的类型。 – 2011-03-24 06:10:27

发现问题。托卡马克使用特殊的分配方法来避免异常(我认为)。对于每个新的对象实例,它做类似于:

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

因此,对于对象工作得很好,问题是数组。随着阵列,托卡马克代码是这样做的:

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

的事情在这里似乎是NDK编译器使用4字节相比(32位INT)数组索引的更多,如果我的代码扩展为+8那么一切都只是工作。