28

从C++ std::shared_ptr 原理来看看栈溢出的危害

 5 years ago
source link: http://satanwoo.github.io/2019/01/26/shared-ptr/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C++ std::shared_ptr 实现原理

上周五排查了一个由于 XXX模块 操作疏忽导致栈越界引发的 我的模块 的智能指针Crash问题,因此稍微研究了一下,以作参考:

shared_ptr共享被管理对象,同一时刻可以有多个shared_ptr拥有对象的所有权,当最后一个shared_ptr对象销毁时,被管理对象自动销毁

shared_ptr 实现

aEVZryI.png!web

简单来说, shared_ptr 实现包含了两部分,

  • 一个指向堆上创建的对象的裸指针
  • 一个指向内部隐藏的、共享的管理对象。

第一部分没什么好说的,第二部分是需要关注的重点:

  • use_count ,当前这个堆上对象被多少对象引用了,简单来说就是引用计数。
  • weak_count ,这个管理对象被多少个智能指针共享了,简单来说就是 管理对象 的引用计数。

不同指针创建的对同一个堆上对象的智能管理,并不共享管理对象,因此存在 double free 的可能性

_shared_ptr 直接包含的裸指针是为了实现一般指针的->,*等操作,通过 __shared_count 间接包含的指针是为了管理对象的生命周期,回收相关资源。

换句话说, __shared_count 内部的 use_count 主要用来标记被管理对象的生命周期, weak_count 主要用来标记管理对象的生命周期。

问题原因

了解了原理,可以看出 std::share_ptr 本身的 _M_ptr 指向了堆上通过 new 创建的对象。但是其自身这个 _M_ptr 却会如果在不当操作上,被修改,比如栈越界操作,就会被破坏,导致产生对非法对象的访问:

int i = 5;
NSLog(@"i address is %p", &i);

XXX::XX df = XXX::XX::buildDataFrame();
NSLog(@"sp0 address is %p", &df);

int a[1] = {1};

NSLog(@"k address is %p", a);

for (int i = 0; i < 10; i++) {
    a[i] = i;
}

NSLog(@"haha");

上述这段代码就会引发问题,这里 XXX::XX 的具体内部设计使用了经典的RAII,下文再表。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK