<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      -fno-rtti導致的慘案(object has invalid vptr)

      PS:要轉載請注明出處,本人版權所有。

      PS: 這個只是基于《我自己》的理解,

      如果和你的原則及想法相沖突,請諒解,勿噴。

      環境說明
      • Ubuntu 24.04.2 LTS \n \l
      • gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)

      前言


      ??對于C++程序開發來說,MemoryLeek/UndefinedBehavior 等問題,簡直就是大型開發過程必定會出現的問題。那么我們怎么嘗試減少這些問題,在我的日常開發中,大概有以下方案:

      • 對于開發過程中來說,在c++11以后,標準庫引入了智能指針,然后增強開發者內存所有權意識等,可以有效減少MemoryLeek問題。
      • 對于測試發布流程來說,我們常常引入了valgrind/sanitizer減少MemoryLeek/UndefinedBehavior 等問題。

      ??尤其是對于新的編譯器來說,sanitizer還是比較好用的。最近遇到了一個不是那么常見的sanitizer ub錯誤,我覺得非常有趣,可以分享一下。





      -fno-rtti導致的慘案


      ??下面的圖片是出現的問題現場截圖:

      rep_img

      ??上圖一看就是ub錯誤,具體是什么原因,還要分析一番。



      問題最小用例復現

      ??下面是最小的復現用例:

      //l.cpp
      #include <memory>
      
      #include "A.hpp"
      
      
              void B::p(){printf("p(): class B\n");}
              void B::p1(){printf("p1(): class B\n");}
      
              void A::p(){printf("p(): class A\n");}
              void A::p1(){printf("p1(): class A\n");}
      
      
      std::shared_ptr<A> my_A(new A());
      
      void i(){
      
              my_A->p1();
      }
      
      //l.hpp
      void i();
      
      //l.hpp
      void i();
      
      //A.hpp
      #include <cstdio>
      class B{
              public:
              virtual void p();
              virtual void p1();
      
      };
      class A:public B{
              public:
                      void p();
                      void p1();
      };
      
      //t.cpp
      #include <memory>
      #include <cstdio>
      
      #include "A.hpp"
      #include "l.hpp"
      
      std::shared_ptr<A> my_AA(new A());
      
      int main(int argc, const char* argv[])
      {
              my_AA->p();
              i();
              return 0;
      }
      
      g++ -c l.cpp -O3 -fPIC -fsanitize=undefined
      
      g++ -shared -o libA.so l.o -O3
      
      g++ t.cpp -o t -O3 -I. -L . -l A -fno-rtti -fsanitize=undefined -Wl,-rpath=. 
      
      # ./t 運行就會得到如上的錯誤
      

      注意上述例子用到了多態類,這和我原始工程中類似,但是實際情況中,一個普通的類也會有同樣的問題,具體原因,見如下分析。



      問題分析

      ??首先我們看看出現的_Sp_counted_base/_Sp_counted_ptr是什么,這個通過報錯,看起來像shared_ptr引用計數相關,我們看看其實際的代碼大致關系如下:

          template<typename _Tp>
          class shared_ptr : public __shared_ptr<_Tp>
          {
              //...
          }
      
      
          class __shared_ptr
          : public __shared_ptr_access<_Tp, _Lp>
          {
              //...
              __shared_count<_Lp>  _M_refcount;    // Reference counter.
          }
      
      
          template<_Lock_policy _Lp>
          class __shared_count
          {
              template<typename _Ptr>
              explicit
              __shared_count(_Ptr __p) : _M_pi(0)
              {
              __try
                  {
                      _M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
                  }
              __catch(...)
                  {
                      delete __p;
                      __throw_exception_again;
                  }
              }
              //...
              _Sp_counted_base<_Lp>*  _M_pi;
          }
      
      
          template<typename _Ptr, _Lock_policy _Lp>
          class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
          {
              //...
          }
      
          template<_Lock_policy _Lp = __default_lock_policy>
          class _Sp_counted_base
          : public _Mutex_base<_Lp>
          {
              //...
          }
      

      ??我們使用如下命令,看一下t和libA.so的_Sp_counted_ptr符號,我們發現對于相同的符號來說,其大小不一樣。

      # readelf -sW libA.so |grep counted_ptr
          24: 0000000000005160    54 OBJECT  WEAK   DEFAULT   16 _ZTSSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE
          25: 0000000000003970   338 FUNC    WEAK   DEFAULT   14 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EED1Ev
          27: 0000000000003970   338 FUNC    WEAK   DEFAULT   14 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EED2Ev
          30: 0000000000003790     7 FUNC    WEAK   DEFAULT   14 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE14_M_get_deleterERKSt9type_info
          33: 0000000000006d80    56 OBJECT  WEAK   DEFAULT   22 _ZTVSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE
          40: 0000000000006cf0    24 OBJECT  WEAK   DEFAULT   22 _ZTISt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE
          44: 0000000000003c30   489 FUNC    WEAK   DEFAULT   14 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE10_M_destroyEv
          48: 0000000000003880   225 FUNC    WEAK   DEFAULT   14 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE10_M_disposeEv
          53: 0000000000003ad0   350 FUNC    WEAK   DEFAULT   14 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EED0Ev
      
      # readelf -sW t |grep counted_ptr
          20: 0000000000002700   172 FUNC    WEAK   DEFAULT   16 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EED2Ev
          22: 0000000000002700   172 FUNC    WEAK   DEFAULT   16 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EED1Ev
          23: 0000000000002870   233 FUNC    WEAK   DEFAULT   16 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE10_M_destroyEv
          24: 00000000000027b0   188 FUNC    WEAK   DEFAULT   16 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EED0Ev
          26: 00000000000026a0    92 FUNC    WEAK   DEFAULT   16 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE10_M_disposeEv
          30: 0000000000002610     7 FUNC    WEAK   DEFAULT   16 _ZNSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE14_M_get_deleterERKSt9type_info
          32: 0000000000005ca0    56 OBJECT  WEAK   DEFAULT   24 _ZTVSt15_Sp_counted_ptrIP1ALN9__gnu_cxx12_Lock_policyE2EE
      

      ??這個時候我們想一下-fno-rtti的作用,其作用是禁用typeinfo+dynamic_cast,某些情況下可以提升執行性能。然后根據錯誤中的提示(object has invalid vptr),必定和其虛表有關系,那就意味著_Sp_counted_base/_Sp_counted_ptr的虛表存在異常。

      ??用ida查看t和libA.so中std::_Sp_counted_base的虛表內容,他們如下圖:

      rep_img
      rep_img

      ??注意,一般的虛表結構如下:

      +-------------------+
      |  Offset-to-Top    | (通常為負數,用于多重繼承)
      +-------------------+
      |  type_info 指針    | (用于 RTTI)
      +-------------------+
      |  虛函數1 的地址    |
      +-------------------+
      |  虛函數2 的地址    |
      +-------------------+
      |      ...          |
      

      ??從上面的圖和虛表結構可知,就是兩個同名的vtable內容不一樣,導致了此問題。解決方法也很簡單,大家使用同樣的編譯參數即可。





      后記


      ??c++的一些錯誤是非常有趣的,值得細看。

      參考文獻




      打賞、訂閱、收藏、丟香蕉、硬幣,請關注公眾號(攻城獅的搬磚之路)
      qrc_img

      PS: 請尊重原創,不喜勿噴。

      PS: 要轉載請注明出處,本人版權所有。

      PS: 有問題請留言,看到后我會第一時間回復。

      posted on 2025-08-28 13:11  SkyOnSky  閱讀(106)  評論(0)    收藏  舉報

      導航

      主站蜘蛛池模板: 在线 欧美 中文 亚洲 精品| 激情五月天一区二区三区| 啊轻点灬大JI巴太粗太长了在线| 国产高清小视频一区二区| 久久综合给合久久狠狠狠| 久久人人97超碰爱香蕉| 少妇午夜啪爽嗷嗷叫视频| 国产精品天干天干综合网| 日韩精品一卡二卡三卡在线| 中文字幕在线不卡一区二区 | 丝袜国产一区av在线观看| 中文字幕日韩精品人妻| 中文字幕亚洲综合第一页| 日本三级香港三级三级人妇久| 国产不卡一区二区在线| 国产午夜91福利一区二区| 免费久久人人爽人人爽AV| 久久精品国产精品亚洲综合| 妇女自拍偷自拍亚洲精品| 精品久久精品午夜精品久久| 久久久久青草线蕉亚洲| 99热久久这里只有精品| 秋霞电影院午夜无码免费视频| 国产成人无码aa精品一区| 日韩熟女乱综合一区二区| 亚洲精品成人片在线观看精品字幕| 色综合色综合久久综合频道88| 精品无人区一区二区三区在线| 亚洲精品日韩中文字幕| 久久香蕉国产线看观看猫咪av| 亚洲av产在线精品亚洲第一站 | 欧美寡妇xxxx黑人猛交| 亚洲码国产精品高潮在线| 人成午夜免费大片| 精品人妻中文无码av在线| 国产一区二区日韩在线| 亚洲乱妇老熟女爽到高潮的片| 灯塔市| 视频一区视频二区中文字幕| 少妇熟女久久综合网色欲| 亚洲人成网站77777在线观看|