apache / brpc

brpc is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "brpc" means "better RPC".
https://brpc.apache.org
Apache License 2.0
16.49k stars 3.96k forks source link

使用 bthread 出现异常情况 #1264

Open wasphin opened 4 years ago

wasphin commented 4 years ago

Describe the bug (描述bug)

class B1 {
public:
    virtual ~B1() {}
};
class B2 {
public:
    virtual ~B2() {}

    static void* RunThis(void *arg) {
        static_cast<B2*>(arg)->Run();
        return nullptr;
    }
    void Run() {
        // inotifywait_child 是一个 boost::process::child, 监视文件变更, 然后上报
        while (inotifywait_child->running() && std::getline(*_out, file)) {
            try {
                foo();
            } catch (...) {
            }
        }
    }
    virtual void foo() {}

    void bar() {
        bthread_t tid;
        bthread_start_background(&tid, nullptr, RunThis, this);
        // 改用 BTHREAD_ATTR_PTHREAD 后, 未复现
        // bthread_start_background(&tid, &BTHREAD_ATTR_PTHREAD, RunThis, this);
    }
};
class D1 : public B1, public B2 {
public:
    void foo() override;

}

B2::bar() 中使用默认参数 bthread_start_background 执行了类似上面代码的任务, 结果崩溃在 D1::foo 部分, 此时显示 this=0x0.

改用 pthread_create 或添加 BTHREAD_ATTR_PTHREAD 属性后正常, 这个是使用方式不对还是有什么可能的问题?

To Reproduce (复现方法) 暂无最小复现例子.

Expected behavior (期望行为) 使用默认参数

Versions (各种版本) OS: RHEL/CentOS 8 Compiler: 8.3.1 brpc: 7bda11bc312d422b3e293b19b8b82a711da26c94 protobuf: 3.5.0

Additional context/screenshots (更多上下文/截图)

gydong commented 4 years ago

把 RunThis 的实现和调用代码也贴一下看看

wasphin commented 4 years ago

把 RunThis 的实现和调用代码也贴一下看看

已更新到原描述中. 这个应该不是 bthread 的理想使用场景, 但是想确认下根源.

jamesge commented 4 years ago

@wasphin 你试试看把class D1 : public B1, public B2改成class D1 : public B2, public B1还会挂么,看上去是c++多重继承导致的内存排列问题,static_cast<B2*>(arg)和D1继承B2的方式是冲突的。

wasphin commented 4 years ago

@wasphin 你试试看把class D1 : public B1, public B2改成class D1 : public B2, public B1还会挂么,看上去是c++多重继承导致的内存排列问题,static_cast<B2*>(arg)和D1继承B2的方式是冲突的。

有试过, 还是会挂, ~印象中挂的地方不一样了, 是一个 assert pid 的部分~. 重新试了一下, 调整继承顺序后报错一样.

0x00000000004b2886 in xxx (this=0x0, path=<error reading variable: Cannot access memory at address 0x8>) xxx
wasphin commented 4 years ago

另外这个更像一个 UB, 代码两个部分都使用了类似的方式, 而另一个地方则未触发该问题. 并且, 在另一个测试环境(类 CentOS7)下的 Release 版本报错也不一致.

gydong commented 4 years ago

1、RunThis 的调用处的代码还没贴上来 2、打印一下static_cast后的指针看看是不是个nullptr

wasphin commented 4 years ago

1、RunThis 的调用处的代码还没贴上来

已更新, 在 B2::bar() 中调用的 bthread_start_background

2、打印一下static_cast后的指针看看是不是个nullptr

不是 nullptr

cdjingit commented 4 years ago

方便能贴个可以复现的完整代码。是不是访问了已经析构的D1

wasphin commented 4 years ago

方便能贴个可以复现的完整代码。

先贴问题出来主要也是想看看有没有什么明显没注意到的地方. 可复现的例子后面我再整理一下.

是不是访问了已经析构的D1

D1 肯定没有析构的, 创建后直到退出才会析构.

cdjingit commented 4 years ago

方便能贴个可以复现的完整代码。

先贴问题出来主要也是想看看有没有什么明显没注意到的地方. 可复现的例子后面我再整理一下.

是不是访问了已经析构的D1

D1 肯定没有析构的, 创建后直到退出才会析构.

D1是在B2基类部分前析构的,D1析构时有没有stop/join bthread? 因为这里的实现方式很容易出问题。

wasphin commented 4 years ago

D1是在B2基类部分前析构的,D1析构时有没有stop/join bthread? 因为这里的实现方式很容易出问题。

明白说的这个点, D1 析构时也确实会调到 stop/join bthread, D1 在测试时是没有析构的.