Skip to content

fix(syscall-stat): improve builtin flow - #115

Open
yuKing123-king wants to merge 1 commit into
DKapture:mainfrom
yuKing123-king:test/add-syscall-stat-BUILTIN
Open

fix(syscall-stat): improve builtin flow#115
yuKing123-king wants to merge 1 commit into
DKapture:mainfrom
yuKing123-king:test/add-syscall-stat-BUILTIN

Conversation

@yuKing123-king

@yuKing123-king yuKing123-king commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

对本次 syscall-stat 工具修改的内容

  1. 补齐 BUILTIN 测试入口
    • 改为通过返回值处理参数解析结果,增强健壮性。

@rwenz2004

Copy link
Copy Markdown

注意提交信息,应该是fix不是test

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from 220b53c to c1c5e24 Compare July 28, 2026 01:37
@yuKing123-king

Copy link
Copy Markdown
Contributor Author

注意提交信息,应该是fix不是test

ok,后面统一会改成fix

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from c1c5e24 to 1cf902e Compare July 31, 2026 03:20
@yuKing123-king yuKing123-king changed the title test: add support syscall-stat builtin testing and improve runtime fe… fix(syscall-stat): improve builtin flow and fix stats iteration/top parsing Jul 31, 2026
Comment thread observe/syscall-stat.cpp
static std::atomic<bool> exit_flag(false); // Flag to signal exit
static std::atomic<bool> exit_flag(false);

#ifdef BUILTIN

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个宏的引入是不必要的,局部函数直接用static就行,没必要考虑这种兼容性

Comment thread observe/syscall-stat.cpp

// Parse command line arguments
void parse_args(int argc, char **argv)
static int parse_args(int argc, char **argv)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

其他局部函数也应该像这样修改,不要使用BUILTIN_LOCAL宏

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

所有局部函数已改成static

Comment thread observe/syscall-stat.cpp Outdated
int *log_fd,
int *stats_fd
){
test_name = "syscall-stat"; // 告诉 mock/test 框架当前正在运行哪个工具

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

中文注释只需要保留关键部分

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已压缩成简洁的英文

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from 1cf902e to 13a61c2 Compare July 31, 2026 03:37
Comment thread observe/syscall-stat.cpp Outdated
// stats

while (0 == bpf_map_get_next_key(stats_fd, &key, &nxt_key))
int ret = bpf_map_get_next_key(stats_fd, NULL, &nxt_key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这儿为啥改动,没有必要的话,无关改动,不要引入进来

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这的改动是有必要的,因为原来的代码是

while (0 == bpf_map_get_next_key(stats_fd, &key, &nxt_key))
		{
			info sys_stat;
			bpf_map_lookup_elem(stats_fd, &nxt_key, &sys_stat);
			if (nxt_key >= sizeof(sys_tbl) / sizeof(sys_tbl[0]))
			{
				key = nxt_key;
				continue;
			}
			if (sys_stat.cnt == 0)
			{
				key = nxt_key;
				continue;
			}
			stats.push_back({nxt_key, sys_stat});
			total += sys_stat.cnt;
			memset(&sys_stat, 0, sizeof(sys_stat));
			bpf_map_update_elem(stats_fd, &nxt_key, &sys_stat, BPF_ANY);
			key = nxt_key;
		}

while (0 == bpf_map_get_next_key(stats_fd, &key, &nxt_key))这里循环条件一开始就调用next_key,但是key一开始是0,next_key就是1,并且后面用来查询stats_fd这个map一直都用的next_key,也就是说后面的代码永远都不会去获取key=0的stats_fd,所以最后的结果永远都不会有系统调用号为0的read,这个问题是我用syscall-stat去追踪ls的系统调用的时候发现没有read这个系统调用,ls是查询功能,所以理论上来说肯定会调用read这个系统调用的。后来我调整遍历逻辑,确保从代码可以从第一个 key 开始完整遍历。再去使用syscall-stat去追踪ls的系统调用时,结果中就有read这个系统调用了

Comment thread observe/syscall-stat.cpp Outdated
{
pr_error("Error polling ring buffer: %d\n", err);
sleep(5); // Sleep before retrying
std::this_thread::sleep_for(std::chrono::microseconds(5)); // Sleep before retrying

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

解释下,为什么改这

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为我觉得这里的sleep(5); 是ring_buffer__poll() 出错后,等待5秒之后再重新试一下,避免错误路径一直占用cpu,但是5s我觉得太久了,会影响使用性能所以改成了5微秒,如果感觉太短也可以改回5s

Comment thread observe/syscall-stat.cpp Outdated
{"pid2pathhash",{sizeof(pid_t), sizeof(u32), 1024, BPF_MAP_TYPE_LRU_HASH}},
{"logs", {0, 0, 1024 * 1024, BPF_MAP_TYPE_RINGBUF}},
};
static std::atomic<int> *condition;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这几个静态变量,都没有使用

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

condition这个使用了,这个是.cpp代码和test代码用来同步状态的
{"pid2pathhash",{sizeof(pid_t), sizeof(u32), 1024, BPF_MAP_TYPE_LRU_HASH}},
{"logs", {0, 0, 1024 * 1024, BPF_MAP_TYPE_RINGBUF}},这两个确实没使用,我现在删除

Comment thread observe/syscall-stat.cpp Outdated
// stats

while (0 == bpf_map_get_next_key(stats_fd, &key, &nxt_key))
int ret = bpf_map_get_next_key(stats_fd, NULL, &nxt_key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

拆成两个提交,bug修复一个

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的

@xu-lang xu-lang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

请先修复评审问题

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from 13a61c2 to fd937c9 Compare August 4, 2026 08:10
@yuKing123-king yuKing123-king changed the title fix(syscall-stat): improve builtin flow and fix stats iteration/top parsing fix(syscall-stat): improve builtin flow Aug 4, 2026
@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from fd937c9 to e0ac09a Compare August 4, 2026 08:21
@yuKing123-king

Copy link
Copy Markdown
Contributor Author

请先修复评审问题

1.多余静态变量已删除
2.已经将修复bug部分,单独提出一个pr

@xu-lang xu-lang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

问题还是很多,以上只是部分,更严重的是修改思路框架设计过于随意,过于依赖全局变量

Comment thread observe/syscall-stat.cpp
free(buf);
exit(0);
break;
return 1; // Indicate that help was displayed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里为什么返回1,破坏了原来的逻辑

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 原来这里是exit(0),exit和return的区别是,exit会立即终止当前线程,后续代码全部不执行,而return是终止当前函数,后面代码正常执行。
  2. 如何这里还是exit的话,线程终止后面代码不执行,没有相关状态变量传到syscall-stat-test.cpp中,syscall-stat-test.cpp会正常执行,但是无法区分测试失败是因为"用户请求了帮助"还是"程序崩溃",所以每个地方都需要一个返回值参数返回给syscall-stat-test.cpp区分是什么原因引起的测试失败。
  3. 如果这里一定需要exit(0)这样的语义,这里可以通过定义BUILTIN这个宏来继续使用exit(0)。

Comment thread observe/syscall-stat.cpp Outdated
stats_fd = bpf_get_map_fd(obj->obj, "syscall_stat", goto err_out);

#ifdef BUILTIN
*filter_fdp = filter_fd;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么把fd传出去,外面保证fd的生命周期了吗?是否导致fd泄漏

Comment thread observe/syscall-stat.cpp Outdated
*condition = 1;
while(!exit_flag)
{
std::this_thread::sleep_for(std::chrono::microseconds(5));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???空转?

Comment thread observe/syscall-stat.cpp Outdated
}

#ifdef BUILTIN
*conditionPrint = 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要这样传参出去,一堆这种出参,极其ugly

std::atomic<int> *conditionp,
std::atomic<int> *conditionPrintP,
std::atomic<bool> **exit_flagp,
int *filter_fd,
int *stats_fd

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from e0ac09a to 20d00b5 Compare August 6, 2026 06:41
Comment thread observe/syscall-stat.cpp
local_map_info = {
{"filter", {sizeof(u32), sizeof(struct Rule), 1, BPF_MAP_TYPE_HASH}},
{"syscall_stat",{sizeof(u32), sizeof(struct info), 453, BPF_MAP_TYPE_ARRAY}},
{"logs", {0, 0, 1024 * 1024, BPF_MAP_TYPE_RINGBUF}},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的filter和syscall_stat和logs,虽然在当前代码中没有使用,这个local_map_info是传给mock.cpp去生成3个伪map供syscall-stat-test.cpp中使用

Comment thread observe/syscall-stat.cpp Outdated
char *end = nullptr;
errno = 0;
long val = strtol(optarg, &end, 10);
if (end == optarg || *end != '\0' || errno == ERANGE || val < 0 || (unsigned long)val > UINT32_MAX)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的修改是为了检验用户输入负数,字母等非法参数,例如-1,12abc,abc这样的参数,可以提示用户参数输错

Comment thread observe/syscall-stat.cpp
free(buf);
exit(0);
break;
return 1; // Indicate that help was displayed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 原来这里是exit(0),exit和return的区别是,exit会立即终止当前线程,后续代码全部不执行,而return是终止当前函数,后面代码正常执行。
  2. 如何这里还是exit的话,线程终止后面代码不执行,没有相关状态变量传到syscall-stat-test.cpp中,syscall-stat-test.cpp会正常执行,但是无法区分测试失败是因为"用户请求了帮助"还是"程序崩溃",所以每个地方都需要一个返回值参数返回给syscall-stat-test.cpp区分是什么原因引起的测试失败。
  3. 如果这里一定需要exit(0)这样的语义,这里可以通过定义BUILTIN这个宏来继续使用exit(0)。

Comment thread observe/syscall-stat.cpp
Usage(argv[0]);
free(buf);
exit(-1);
return -1;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里与上述问题一致

Comment thread observe/syscall-stat.cpp
int slen = strlen(sys_tbl[i]);
if (!sys_tbl[i])
continue;
int slen = strlen(sys_tbl[i]);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的修改是防止sys_tbl[i]是NULL,导致strlen(NULL)

Comment thread observe/syscall-stat.cpp
if (total)
{
printf("\ntotal: %d\n", total);
printf("\ntotal: %u\n", total);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的修改是因为上面定义的total是u32 total = 0;,是u32类型不是int类型

Comment thread observe/syscall-stat.cpp
if (0 != syscall_stat_bpf::attach(obj))
{
exit(-1); // Attach BPF program
goto err_out; // Attach BPF program

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里不使用exit(-1)是因为如果上面的syscall_stat_bpf::open_and_load();成功了,但是syscall_stat_bpf::attach(obj)失败了,但是使用exit(-1)的话,会终止整个程序,导致后面的obj释放无法执行,造成泄露

Comment thread observe/syscall-stat.cpp
stats_fd = bpf_get_map_fd(obj->obj, "syscall_stat", goto err_out);

#ifdef BUILTIN
runtime_state->fds_promise.set_value(SyscallStatFds{filter_fd, stats_fd});

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 这里向外传filter_fd和stat_fd的原因是,syscall-stat-test.cpp需要这两个fd去查询mock.cpp生成的rule和stat 这两个map的数据,以便向 map 中注入测试事件(bpf_map_update_elem(stats_fd, ...))并验证过滤规则(bpf_for_each_map_elem(filter_fd, ...))。
  2. 这里只是传了两个整数值(fd 的拷贝),filter_fd和stat_fd的生命周期依旧还是本程序中控制,在 err_out 标签处通过 syscall_stat_bpf::destroy(obj) 统一释放,测试线程仅持有 fd 的整数副本用于读写操作,不负责关闭,因此不会造成 fd 泄漏或双重释放。

@xu-lang

xu-lang commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

/oc

1 similar comment
@rwenz2004

Copy link
Copy Markdown

/oc

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

User rwenz2004 does not have write permissions

github run

@rwenz2004

Copy link
Copy Markdown

/review 检视一下

@rwenz2004

Copy link
Copy Markdown

/review

@github-actions

Copy link
Copy Markdown

Preparing review...

1 similar comment
@github-actions

Copy link
Copy Markdown

Preparing review...

@rwenz2004

Copy link
Copy Markdown

/review

@github-actions

Copy link
Copy Markdown

Preparing review...

@rwenz2004

Copy link
Copy Markdown

/review

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit 026ce7f)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

错误路径返回值未设置

syscall_stat_main(及非 BUILTIN 模式下的 main)中,多处错误路径通过 goto err_out 跳转到清理标签,但变量 ret 在这些路径上仍保持 parse_args 返回的 0。例如 BPF attach 失败、bpf_get_map_fd 失败、bpf_map_update_elem 失败、ring_buffer__new 失败、pthread_create 失败等场景,函数最终 return ret 返回 0,将错误误报为成功。在 BUILTIN 模式下,测试框架会误认为测试通过;在独立运行模式下,shell 脚本检查退出码也会得到错误的结果。应在每处 goto err_out 前设置 ret = -1,或在 err_out 标签处统一设置。

		goto err_out; // Attach BPF program
	}

	// Get file descriptor for filter map and update it with the rule
	filter_fd = bpf_get_map_fd(obj->obj, "filter", goto err_out);
	stats_fd = bpf_get_map_fd(obj->obj, "syscall_stat", goto err_out);
#ifdef BUILTIN
	runtime_state->fds_promise.set_value(SyscallStatFds{filter_fd, stats_fd});
#endif
	if (0 != bpf_map_update_elem(filter_fd, &key, &rule, BPF_ANY))
	{
		printf("Error: bpf_map_update_elem");
		goto err_out; // Handle error
	}

	// Create a ring buffer for logs
	log_map_fd = bpf_get_map_fd(obj->obj, "logs", goto err_out);
	rb = ring_buffer__new(log_map_fd, handle_event, NULL, NULL);
	if (!rb)
	{
		goto err_out; // Handle error
	}

	// Create a thread for processing the ring buffer
	if (pthread_create(&t1, NULL, ringbuf_worker, NULL) != 0) 
	{
		pr_error("Failed to create ringbuf thread");
		goto err_out;
	}
	if (pthread_create(&t2, NULL, timer_task, NULL) != 0) 
	{
		pr_error("Failed to create timer thread");
		pthread_kill(t1, SIGINT);
		pthread_join(t1, NULL);
		goto err_out;
	}
#ifndef BUILTIN
	follow_trace_pipe(); // Read trace pipe
#else
	{
		std::lock_guard<std::mutex> lock(runtime_state->sync.m);
		runtime_state->sync.init_done = true;
	}
	runtime_state->sync.cv.notify_all();
	{
		std::unique_lock<std::mutex> lock(runtime_state->sync.m);
		runtime_state->sync.cv.wait(lock, [&] { return runtime_state->sync.exit_requested; });
	}
#endif
	pthread_kill(t1, SIGINT);
	pthread_join(t1, NULL);
	pthread_kill(t2, SIGINT);
	pthread_join(t2, NULL);
err_out:
	if (rb)
	{
		ring_buffer__free(rb); // Free ring buffer if allocated
	}
	syscall_stat_bpf::detach(obj);	// Detach BPF program
	syscall_stat_bpf::destroy(obj); // Clean up BPF program
	return ret;						// Exit successfully

@rwenz2004

Copy link
Copy Markdown

/review 检查一下代码中可能存在哪些安全风险

@github-actions

Copy link
Copy Markdown

Preparing review...

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from 20d00b5 to 967e9da Compare August 11, 2026 06:46
@yuKing123-king

Copy link
Copy Markdown
Contributor Author

/review 检查一下代码中可能存在哪些安全风险

@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit 967e9da

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from 967e9da to 026ce7f Compare August 11, 2026 07:45
@yuKing123-king

Copy link
Copy Markdown
Contributor Author

/review 检查一下当前代码存在哪些安全风险的问题,代码不规范的地方

@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit 026ce7f

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from 026ce7f to cb5591a Compare August 11, 2026 08:40
@yuKing123-king

Copy link
Copy Markdown
Contributor Author

/review 检查一下当前代码存在哪些安全风险的问题,代码不规范的地方

@github-actions

Copy link
Copy Markdown

Preparing review...

@yuKing123-king

Copy link
Copy Markdown
Contributor Author

/review 检查一下当前代码存在哪些安全风险的问题,代码不规范的地方

@github-actions

Copy link
Copy Markdown

Preparing review...

@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from cb5591a to c87fcf2 Compare August 13, 2026 08:22
Signed-off-by: Wang Yu <wangyu6@uniontech.com>
@yuKing123-king
yuKing123-king force-pushed the test/add-syscall-stat-BUILTIN branch from c87fcf2 to 9b69265 Compare August 13, 2026 08:50
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.

3 participants