简体   繁体   中英

Why do I get a heap buffer overflow simply by declaring a shared_ptr member variable?

Just ran into this very strange bug. I'm getting crashes due to memory errors after adding a new shared_ptr instance variable in an existing containing class.

When I run with the AddressSanitizer in Xcode, it reports a heap buffer overflow on the new iVar, when an object of the containing class is instantiated (ie, at its CTOR).

I can't replicate this in a simple system, and this is proprietary code (so I can't show it fully here). However, I can trigger the error simply by declaring a new shared_ptr instance variable, of a simple type (int).

My classes are basically

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

...

and that runs fine. But when I try this (adding one line: the new 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
};

I get a heap buffer overflow at the MyContainingClass CTOR, even without trying to allocate the DifferentHelperObject. . (I get the same error if I do create the smart pointer in the CTOR.)

If I change the order of declaration , AddressSanitizer reports the error at HelperObject instead of DifferentHelperObject (ie, whichever one is declared second).

DifferentHelperObject is a fairly simple type; it contains only simple POD members and methods (no pointers, arrays, smart pointers, etc.) So I tried replacing it with something really simple: 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

and I now get the heap buffer overflow on the shared_ptr for _anInt.

This is what the AddressSanitizer output looks like for the last case:

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)

使用 AddressSanitizer 时的实际错误

and the call stack looks like this:

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

I've been trying to understand the AddressSanitizer output; the shadow memory addresses don't seem to map correctly onto actual program memory (mutliplying by 8, there is still an offset. So any help understanding how the AddressSanitizer output above could point me to the actual problem (or suggestions what the actual problem might be) would be greatly appreciated.

very strange bug. I'm getting crashes due to memory errors after adding a new shared_ptr instance variable in an existing containing class.

I can't replicate this in a simple system

Quite often this is the result of rebuilding some, but not all of the code which includes MyContainingClass.h .

Try doing a "from scratch" build. Chances are, both the crash and the AddressSanitizer problems will disappear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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