不可能的堆栈跟踪?尽管已检查

问题描述 投票:1回答:1
但使用this = nullptr违反访问

我正在分析一个相当复杂的项目中的罕见但一致的崩溃,这是这些“不可能的堆栈跟踪”之一,意思是:乍一看,一切看起来都还不错。

崩溃本身是“引发未处理的异常:读取访问冲突。这是nullptr。”。

堆栈当前帧中的代码如下:

FT6VehiclePathCheckpoint AT6Building::GetVehicleCheckpoint() const
{
    FT6VehiclePathCheckpoint targetCheckpoint = FT6VehiclePathCheckpoint();
    if (GetBusStopComponent() != nullptr)
    {
        ...

并且崩溃在“ if(Get(BusStopComponent()!= nullptr)”行中。函数“ GetBusStopComponent()”本身是该对象的成员变量的内联吸气剂,因此它不会显示在跟踪中。另外,在内存转储中,“ this”的确为0。到目前为止很好。

但是,其正上方的堆栈框架看起来像这样:

const AT6Building* portalBuildingByLocation = pathFinder != nullptr ? pathFinder->GetPortalBuildingByLocation(startLocation) : GetNearestDrivewayBuilding();

if (portalBuildingByLocation != nullptr)
{
    startCheckpoint = portalBuildingByLocation->GetVehicleCheckpoint();
}

(指向“ portalBuildingByLocation-> GetVehicleCheckpoint”行)。显然,在调用函数之前先进行了nullptr检查。乍看之下是^^。[下一个我怀疑“ GetVehicleCheckpoint”内的一些内存损坏弄乱了堆栈跟踪?但是那里真的没有什么。 “ FT6VehiclePathCheckpoint”初始化甚至没有构造函数-只是一堆直接初始化的字段(它们都像nullptr和整数文字)。.

该代码是使用cl.exe编译的,并且启用了优化功能,所以我怀疑我在某个地方有一些UB,并且编译器依赖于某些东西。

因此,尽管我在阅读汇编代码时比较菜鸟,但是我还是尝试了。这是GetVehicleCheckpoint函数的反汇编的第一部分:

FT6VehiclePathCheckpoint AT6Building::GetVehicleCheckpoint() const { 00007FF7304714B0 mov qword ptr [rsp+8],rbx 00007FF7304714B5 mov qword ptr [rsp+10h],rsi 00007FF7304714BA push rdi 00007FF7304714BB sub rsp,40h FT6VehiclePathCheckpoint targetCheckpoint = FT6VehiclePathCheckpoint(); 00007FF7304714BF xor eax,eax 00007FF7304714C1 mov qword ptr [rsp+28h],0FFFFFFFFFFFFFFFFh 00007FF7304714CA mov qword ptr [rsp+30h],rax 00007FF7304714CF mov rsi,rcx if (GetBusStopComponent() != nullptr) 00007FF7304714D2 mov rcx,qword ptr [rcx+5F8h]

崩溃在最后一行。好吧,如果我正确地知道了它,它试图从rcx + 5F8h读取一个qword,可能rcx为0? (但是,如果是这样,该错误不应该是“访问冲突,尝试从0x5f8读取”吗?嗯,也许Visual Studio希望提供更多帮助。)。]

此外,我验证了,是的:BusStopComponent确实位于该类的偏移量0x5F8处。

确定,所以我尝试将rcx跟踪到倒数第二个stackframe:

const AT6Building* portalBuildingByLocation = pathFinder != nullptr ? pathFinder->GetPortalBuildingByLocation(startLocation) : GetNearestDrivewayBuilding(); 00007FF730410F21 lea rdx,[rbp-29h] 00007FF730410F25 mov rcx,r12 00007FF730410F28 call AT6AStarPathfinder::GetPortalBuildingByLocation (07FF73059CD30h) 00007FF730410F2D jmp UT6Agent::HandleAgentArrivedToUseCar+34Ah (07FF730410F4Ah) 00007FF730410F2F test r12,r12 00007FF730410F32 je UT6Agent::HandleAgentArrivedToUseCar+342h (07FF730410F42h) 00007FF730410F34 lea rdx,[rbp-29h] 00007FF730410F38 mov rcx,r12 00007FF730410F3B call AT6AStarPathfinder::GetPortalBuildingByLocation (07FF73059CD30h) 00007FF730410F40 jmp UT6Agent::HandleAgentArrivedToUseCar+34Ah (07FF730410F4Ah) 00007FF730410F42 mov rcx,rsi 00007FF730410F45 call UT6Agent::GetNearestDrivewayBuilding (07FF73040DA50h) if (portalBuildingByLocation != nullptr) 00007FF730410F4A test rax,rax 00007FF730410F4D je UT6Agent::HandleAgentArrivedToUseCar+36Ch (07FF730410F6Ch) { startCheckpoint = portalBuildingByLocation->GetVehicleCheckpoint(); 00007FF730410F4F mov rcx,rax 00007FF730410F52 lea rdx,[rbp-9] 00007FF730410F56 call AT6Building::GetVehicleCheckpoint (07FF7304714B0h) 00007FF730410F5B movups xmm0,xmmword ptr [rax]

再次:我对解释程序集并不是很自信,但是从眼神来看,我看到rcx设置为rax中的任何值,并且rax被正确测试为0。所以没有幻想“编译器在优化时删除了nullptr检查”。

任何见解会导致访问冲突?有什么可疑之处可以给我带头吗?

欢呼,伊美。

我正在分析一个相当复杂的项目中的罕见但一致的崩溃,这是这些“不可能的堆栈跟踪”之一,意思是:乍一看,一切看起来都还不错。 ...

Gotcha! (或者更确切地说是David Wohlferd找到了)。

“正上方的堆栈框架”具有误导性,因为代码在同一函数中(在不同的if分支中)多次重复使用此调用。当查看局部变量时,分支路径实际上是不可能的,我将问题确定为另一个数组中的nullptr。

感谢David Wohlferd!死了! :)

c++ assembly stack-trace access-violation
1个回答
2
投票
Gotcha! (或者更确切地说是David Wohlferd找到了)。
© www.soinside.com 2019 - 2024. All rights reserved.