繁体   English   中英

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

[英]how can i debug a C++ delete call on android NDK?

我有一个由Java层管理的Android C ++应用程序。 在此代码中,我使用了一个旧的物理库(tokamak),并且几乎什么也不做,我创建并删除了模拟器,如下所示:

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

在这种情况下,当我调用销毁(并且只调用一次)时,我得到了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");
}

让我感到困惑的是,我在日志中看到dtor complete消息,但没有After After消息和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返回了该指针,而没有先前的释放。 我现在更加困惑

我怀疑DestroySimulatorreinterpret_cast错误。 可能被使用不同类型的比它实际上被删除的对象,调用析构函数错误,这反过来又损害分配器元数据,并导致free崩溃。

删除强制转换的对象时,需要注意两个重要事项:

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

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

找到了问题。 托卡马克使用一种特殊的分配方法来避免异常(我认为)。 对于每个新对象实例化,它都执行以下操作:

// 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编译器对数组索引使用了超过4bytes(32bit int),如果我将代码扩展为+8,那么一切都将正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM