c++ 单元测试中的打桩

gmock

借助于C++运行时多态实现,派生需要打桩的类,使用桩函数覆盖原来的实现,将指向原类的指针指向桩类

mockcpp

// src/UnixCodeModifier.cpp
bool CodeModifier::modify(void *dest, const void *src, size_t size)
{
    // 将 TEXT 段访问权限修改从 x 修改为 rwx
    if(::mprotect(ALIGN_TO_PAGE_BOUNDARY(dest), PAGE_SIZE * 2, PROT_EXEC | PROT_WRITE | PROT_READ ) != 0)
    {
       return false;
    }
    ::memcpy(dest, src, size);
}
// src/JmpCodeX86.h, 相对跳转指令
const unsigned char jmpCodeTemplate[]  = { 0xE9, 0x00, 0x00, 0x00, 0x00 };
#define SET_JMP_CODE(base, from, to) do { \
        *(unsigned long*)(base + 1) = \
            (unsigned long)to - (unsigned long)from - sizeof(jmpCodeTemplate); \
   } while(0)
//  src/JmpCodeX64.h 绝对跳转指令
// FF 25 : JMP /4   jmp absolute indirect
// bytes 2 ~ 5 : operand of jmp, relative to the memory that recorded the thunk addr. it should be zero.
// bytes 6 ~ 13 : the absolute addr of thunk.
const unsigned char jmpCodeTemplate[]  =
   { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

#define SET_JMP_CODE(base, from, to) do { \
       *(uintptr_t *)(base + 6) = (uintptr_t)to; \
   } while(0)

mockcpp打桩c++成员函数

gtest+mockcpp,修改mockcpp以支持C++中类成员函数的mock_XiaoH0_0的博客-CSDN博客_mocker_cpp_virtual

通过成员函数指针获取成员函数的存储位置,然后使用 mockcpp 的打桩机制,将成员函数的入口替换为跳转到桩函数的跳转指令

探究C++中的成员函数指针和虚函数表


class A
{
    public:
        A(int a): a(a) { cnt++; }
        virtual ~A() {}

        string _A() { return "in A"; }

        virtual string str()
        {
            stringstream ss;
            ss << a;
            return ss.str();
        }

        static int getCnt() { return cnt; }
    protected:
        int a;
        static int cnt;
};

int A::cnt = 0;

class B : public A
{
    public:
        B(int a): A(a) {}
        virtual ~B() {}

        string _B() { return "in B"; }

        virtual string str()
        {
            stringstream ss;
            ss << "0x" << std::hex << a << std::dec;
            return ss.str();
        }
};
int main()
{
    A a(1);
    B b(2);

    // 静态成员函数的函数指针, 可以认为是普通的函数指针
    int (*pgetCnt)() = &A::getCnt;
    36f9:       48 8d 05 b7 09 00 00    lea    0x9b7(%rip),%rax        # 40b7 <_ZN1A6getCntEv>
    3700:       48 89 85 50 ff ff ff    mov    %rax,-0xb0(%rbp)
    // 非 virtual 的成员函数
    string (A::*p_A)() = &A::_A;
    3707:       48 8d 05 4a 08 00 00    lea    0x84a(%rip),%rax        # 3f58 <_ZN1A2_AB5cxx11Ev>
    370e:       48 89 45 80             mov    %rax,-0x80(%rbp)
    3712:       48 c7 45 88 00 00 00    movq   $0x0,-0x78(%rbp)
    3719:       00

    // virtual 的成员函数
    string (A::*p_Astr)() = &A::str;
    3747:       48 c7 45 80 11 00 00    movq   $0x11,-0x80(%rbp)
    374e:       00
    374f:       48 c7 45 88 00 00 00    movq   $0x0,-0x78(%rbp)
    3756:       00
    string (B::*p_Bstr)() = &B::str;
    3757:       48 c7 45 90 11 00 00    movq   $0x11,-0x70(%rbp)
    375e:       00
    375f:       48 c7 45 98 00 00 00    movq   $0x0,-0x68(%rbp)
    ((&b)->*p_Astr)();
    3767:       48 8b 45 88             mov    -0x78(%rbp),%rax
    376b:       48 89 c2                mov    %rax,%rdx
    376e:       48 8d 85 50 ff ff ff    lea    -0xb0(%rbp),%rax
    3775:       48 8d 0c 10             lea    (%rax,%rdx,1),%rcx
    3779:       48 8b 45 80             mov    -0x80(%rbp),%rax
    377d:       83 e0 01                and    $0x1,%eax
    3780:       48 85 c0                test   %rax,%rax
    3783:       74 24                   je     37a9 <main+0xf7>
    3785:       48 8b 45 88             mov    -0x78(%rbp),%rax
    3789:       48 89 c2                mov    %rax,%rdx
    378c:       48 8d 85 50 ff ff ff    lea    -0xb0(%rbp),%rax
    3793:       48 01 d0                add    %rdx,%rax
    3796:       48 8b 00                mov    (%rax),%rax
    3799:       48 8b 55 80             mov    -0x80(%rbp),%rdx
    379d:       48 83 ea 01             sub    $0x1,%rdx
    37a1:       48 01 d0                add    %rdx,%rax
    37a4:       48 8b 00                mov    (%rax),%rax
    37a7:       eb 04                   jmp    37ad <main+0xfb>
    37a9:       48 8b 45 80             mov    -0x80(%rbp),%rax
    37ad:       48 8d 55 a0             lea    -0x60(%rbp),%rdx
    37b1:       48 89 ce                mov    %rcx,%rsi
    37b4:       48 89 d7                mov    %rdx,%rdi
    37b7:       ff d0                   callq  *%rax
    37b9:       48 8d 45 a0             lea    -0x60(%rbp),%rax
    37bd:       48 89 c7                mov    %rax,%rdi
    37c0:       e8 0b fb ff ff          callq  32d0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev@plt>
    ((&a)->*p_Astr)();
    37c5:       48 8b 45 88             mov    -0x78(%rbp),%rax
    37c9:       48 89 c2                mov    %rax,%rdx
    37cc:       48 8d 85 40 ff ff ff    lea    -0xc0(%rbp),%rax
    37d3:       48 8d 0c 10             lea    (%rax,%rdx,1),%rcx
    37d7:       48 8b 45 80             mov    -0x80(%rbp),%rax
    37db:       83 e0 01                and    $0x1,%eax
    37de:       48 85 c0                test   %rax,%rax
    37e1:       74 24                   je     3807 <main+0x155>
    37e3:       48 8b 45 88             mov    -0x78(%rbp),%rax
    37e7:       48 89 c2                mov    %rax,%rdx
    37ea:       48 8d 85 40 ff ff ff    lea    -0xc0(%rbp),%rax
    37f1:       48 01 d0                add    %rdx,%rax
    37f4:       48 8b 00                mov    (%rax),%rax
    37f7:       48 8b 55 80             mov    -0x80(%rbp),%rdx
    37fb:       48 83 ea 01             sub    $0x1,%rdx
    37ff:       48 01 d0                add    %rdx,%rax
    3802:       48 8b 00                mov    (%rax),%rax
    3805:       eb 04                   jmp    380b <main+0x159>
    3807:       48 8b 45 80             mov    -0x80(%rbp),%rax
    380b:       48 8d 55 c0             lea    -0x40(%rbp),%rdx
    380f:       48 89 ce                mov    %rcx,%rsi
    3812:       48 89 d7                mov    %rdx,%rdi
    3815:       ff d0                   callq  *%rax
    3817:       48 8d 45 c0             lea    -0x40(%rbp),%rax
    381b:       48 89 c7                mov    %rax,%rdi
    381e:       e8 ad fa ff ff          callq  32d0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev@plt>

    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271