Skip to content

fix(run-queue): catch exceptions from parse_args and handle_event - #154

Open
yuKing123-king wants to merge 1 commit into
DKapture:mainfrom
yuKing123-king:fix/run-queue-catch-throw-in-main
Open

yuKing123-king wants to merge 1 commit into
DKapture:mainfrom
yuKing123-king:fix/run-queue-catch-throw-in-main

Conversation

@yuKing123-king

Copy link
Copy Markdown
Contributor

修复的 Bug

run-queuemain()handle_event() 中存在未被捕获的 C++ 异常,导致进程被 std::terminate 静默 abort,无任何错误提示:

  1. parse_args() 内部通过 std::stoull 解析参数,非法输入会抛 std::invalid_argument / std::out_of_rangeparse_range 里的字符串拼接("..." + range_str)和 long_opt2short_opt 里的 sopts += ... 会抛 std::bad_alloc。这些异常逃逸出 main()std::terminate
  2. handle_event() 在 ringbuf worker 线程中被 ring_buffer__poll 同步回调,其中 runqueques[log->cpu]push_back 会抛 std::bad_alloc。该异常在子线程中抛出,main() 的 try/catch 无法捕获 → 同样 std::terminate

对常驻观测工具而言,失败时应至少打印原因而非静默 abort。

改了哪些地方

  1. main() 中仅包裹 parse_args(argc, args) 一句:
try
{
    parse_args(argc, args);
}
catch (const std::exception &e)
{
    fprintf(stderr, "run-queue: %s\n", e.what());
    goto cleanup;
}
  1. handle_event() 中仅包裹 map/vector 操作:
try
{
    auto it = runqueques.find(log->cpu);
    if (it == runqueques.end())
        runqueques[log->cpu] = std::vector<struct BpfData>();
    runqueques[log->cpu].push_back(*log);
}
catch (const std::bad_alloc &e)
{
    pr_error("handle_event OOM: %s\n", e.what());
    return -1;
}

不涉及 BPF 加载、map 操作、ringbuf 创建等其余语句。

为什么这样修复

  1. 只包会抛异常的语句:经核实 build/observe/run-queue.skel.hrun_queue_bpf::open_and_load / attach / detach / destroy 都是 C 接口,失败返回 NULL 或错误码,不抛 C++ 异常;bpf_get_map_fdring_buffer__newbpf_iter_createreadpthread_create 同理。这些已有 goto cleanup 错误处理,无需也不应被 try/catch 包裹,避免吞掉它们的返回值检查逻辑。真正会抛 C++ 异常的只有 parse_argsstd::stoull + 字符串拼接)和 handle_event(map/vector 分配),故只包这两处。

  2. parse_argscatch (const std::exception &e)std::stoullinvalid_argument/out_of_range,字符串拼接抛 bad_alloc,三者都是 std::exception 派生类,e.what() 能给出具体原因(如 "Invalid number format: abc"),一条 catch 覆盖全部,最小改动。catch 后 goto cleanup 复用既有清理路径(free(buf)rb 判空释放),不增新代码。

  3. handle_event 必须单独包,且只 catch std::bad_alloc:它在 worker 线程里由 ring_buffer__poll 同步回调,不在 main 的 try 作用域内,main 的 catch 根本捕获不到;不单独包的话 worker 线程 OOM 仍 std::terminate。map/vector 对 POD BpfData 的拷贝不抛异常,唯一现实风险是内存分配失败,故精确 catch bad_alloc,不吞其它异常。return -1 符合 libbpf 回调契约(返回负值→ring_buffer__poll 停止并返回错误→worker 线程 err < 0 && err != -EINTR 分支 pr_error 后退出循环),避免线程空转。

验证方式

# 修复前:非法参数静默 abort
./run-queue -u abc
# Aborted (core dumped)   # 无错误提示

# 修复后:打印原因后正常退出
./run-queue -u abc
# run-queue: Invalid number format: abc
# (正常退出码)

Signed-off-by: Wang Yu <wangyu6@uniontech.com>
@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant