为什么我仅仅通过声明一个shared_ptr成员变量就会出现堆缓冲区溢出?

问题描述 投票:0回答:2

刚刚遇到了这个非常奇怪的错误。在现有包含类中添加新的

shared_ptr
实例变量后,由于内存错误,我遇到了崩溃。

当我在 Xcode 中使用 AddressSanitizer 运行时,当实例化包含类的对象时(即在其 CTOR 处),它会报告新 iVar 上的堆缓冲区溢出。

我无法在简单的系统中复制它,并且这是专有代码(所以我无法在这里完整地展示它)。 但是,我可以简单地通过声明一个简单类型(int)的新的shared_ptr实例变量来触发错误。

我的课基本上都是

// MyContainingClass.h

#include <memory>

// Forward
class HelperObject;

class MyContainingClass {

public:
    MyContainingClass();
 ...

private:
    std::shared_ptr<HelperObject> _helperObject;
};

//MyContainingClass.cpp

#include "HelperObject.h"

...

MyContainingClass::MyContainingClass() {
    _helperObject = std::make_shared<HelperObject>();
}

...

运行良好。但是当我尝试这个时(添加一行:新的 iVar)

// MyContainingClass.h

#include <memory>

// Forwards
class HelperObject;
class DifferentHelperObject;

class MyContainingClass {

public:
    MyContainingClass();
 ...

private:
    std::shared_ptr<HelperObject> _helperObject;
    std::shared_ptr<DifferentHelperObject> _differentHelperObject; // <- NEW LINE
};

我在 MyContainingClass CTOR 处遇到堆缓冲区溢出,即使没有尝试分配 DifferentHelperObject。。 (如果我do在CTOR中创建智能指针,我会得到同样的错误。)

如果我更改声明顺序,AddressSanitizer 会在

HelperObject
而不是
DifferentHelperObject
报告错误(即以第二个声明者为准)。

DifferentHelperObject 是一个相当简单的类型;它只包含简单的 POD 成员和方法(没有指针、数组、智能指针等),所以我尝试用一些真正简单的东西替换它:a

std::shared_ptr<int>

    std::shared_ptr<HelperObject> _helperObject;
    std::shared_ptr<int> _anInt; //Adding just this line to otherwise working code causes a crash

我现在在shared_ptr上发现堆缓冲区溢出

_anInt.

这就是最后一种情况的 AddressSanitizer 输出:

SUMMARY: AddressSanitizer: heap-buffer-overflow (/private/var/containers/Bundle/Application/XXXXXXX/MyApp.app/MyApp:arm64+0x10aa0e120) in std::__1::shared_ptr<int>::shared_ptr()+0x4c
Shadow bytes around the buggy address:
  0x0002a56ea260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0002a56ea270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0002a56ea280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0002a56ea290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0002a56ea2a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0002a56ea2b0: 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa
  0x0002a56ea2c0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0002a56ea2d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0002a56ea2e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0002a56ea2f0: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0002a56ea300: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
AddressSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
(lldb) thread info -s
thread #1: tid = 0xb9794, 0x000000012446b328 libclang_rt.asan_ios_dynamic.dylib`__asan::AsanDie(), queue = 'com.apple.main-thread', stop reason = Heap buffer overflow

{
  "access_size": 8,
  "access_type": 1,
  "address": 5023012304,
  "description": "heap-buffer-overflow",
  "instrumentation_class": "AddressSanitizer",
  "pc": 4543308068,
  "stop_type": "fatal_error"
}
(lldb)

调用堆栈如下所示:

Thread 1 Queue : com.apple.main-thread (serial)
#0  0x000000012446b328 in __asan::AsanDie() ()
#1  0x000000012448096c in __sanitizer::Die() ()
#2  0x000000012446890c in __asan::ScopedInErrorReport::~ScopedInErrorReport() ()
#3  0x000000012446813c in __asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) ()
#4  0x000000012446943c in __asan_report_store8 ()
#5  0x000000010ecd6124 in std::__1::shared_ptr<int>::shared_ptr() at /Applications/Xcode_13.2.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/include/c++/v1/memory:2983
#6  0x000000010ecd119c in std::__1::shared_ptr<int>::shared_ptr() at /Applications/Xcode_13.2.1.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/include/c++/v1/memory:2985
#7  0x000000010ecd0f08 in MyContainingClass::MyContainingClass() at /Users/xxx/MyContainingClass.cpp:22
#8  0x000000010ecd1870 in MyContainingClass::MyContainingClass() at /Users/xxx/MyContainingClass.cpp:22

我一直在尝试理解 AddressSanitizer 的输出;影子内存地址似乎没有正确映射到实际程序内存(乘以 8,仍然存在偏移量。因此,任何帮助理解上面的 AddressSanitizer 输出如何可以为我指出实际问题(或建议实际问题可能是什么)是)将不胜感激。

c++ shared-ptr heap-corruption address-sanitizer
2个回答
1
投票

非常奇怪的错误。在现有的包含类中添加新的shared_ptr实例变量后,由于内存错误,我遇到了崩溃。

我无法在简单的系统中复制这个

这通常是重建一些代码的结果,但不是全部,其中包括

MyContainingClass.h

尝试“从头开始”构建。崩溃和 AddressSanitizer 问题很可能都会消失。


0
投票

我也有同样的问题。就我而言,正如@user17732522提到的,这是一种症状,而不是问题本身。

我有静态库和与该库链接的可执行文件。库和可执行文件都包含相同的头文件:

class Config
{
 public:
  bool foo;
  bool bar;
#if defined(DEFINITION)
  bool baz;
#endif
};

DEFINITION
在库中定义,但未在可执行文件中定义

所以下面的课程:

class Class {
// ...
private:
 Config config_;
 std::shared_ptr<int> obj1_;
 std::shared_ptr<HelperObject> obj2_;
}

产生了相同的 ASan 错误:

=================================================================
==7202==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c000000180 at pc 0x000000c33b5d bp 0x7ffc29bc1da0 sp 0x7ffc29bc1d98
WRITE of size 8 at 0x60c000000180 thread T0
    #0 0xc33b5c in std::__1::shared_ptr<HelperObject>::shared_ptr() /usr/local/include/c++/v1/memory:4047:7
© www.soinside.com 2019 - 2024. All rights reserved.