登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
我知道了
查看详情
登录
注册
【AI 应用启航秀】爆款推文视频路径大公开,LUMI 开发者直播本周二揭秘!点击立即预约~
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
8
Star
5
Fork
34
openEuler
/
compiler-docs
代码
Issues
2
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
38
LLVM平行宇宙计划问题修复文档:错误调用导致的incompatible function pointer types问题
已关闭
云沧:6
openEuler:master
云沧
创建于 2024-09-16 16:09
克隆/下载
HTTPS
SSH
复制
下载 Email Patch
下载 Diff 文件
# 1、问题现象 ```c [ 140s] test/regress.c:3707:2: error: incompatible function pointer types initializing 'testcase_fn' (aka 'void (*)(void *)') with an expression of type 'void (void)' [-Wincompatible-function-pointer-types] [ 140s] 3707 | BASIC(event_config_set_max_dispatch_interval, TT_FORK|TT_NEED_BASE), [ 140s] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ 140s] test/regress.h:105:11: note: expanded from macro 'BASIC' [ 140s] 105 | { #name, test_## name, flags, &basic_setup, NULL } [ 140s] | ^~~~~~~~~~~~ [ 140s] <scratch space>:168:1: note: expanded from here [ 140s] 168 | test_event_config_set_max_dispatch_interval [ 140s] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ 140s] test/regress.c:3708:2: error: incompatible function pointer types initializing 'testcase_fn' (aka 'void (*)(void *)') with an expression of type 'void (void)' [-Wincompatible-function-pointer-types] [ 140s] 3708 | BASIC(event_config_set_num_cpus_hint, TT_FORK|TT_NEED_BASE), [ 140s] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ 140s] test/regress.h:105:11: note: expanded from macro 'BASIC' [ 140s] 105 | { #name, test_## name, flags, &basic_setup, NULL } [ 140s] | ^~~~~~~~~~~~ [ 140s] <scratch space>:170:1: note: expanded from here [ 140s] 170 | test_event_config_set_num_cpus_hint [ 140s] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [ 140s] 2 errors generated. ``` # 2、问题定位 ## 2.1、问题定位分析 错误定位: ```c struct testcase_t main_testcases[] = { + /* event.c api tests */ + BASIC(event_base_del_virtual_, TT_FORK|TT_NEED_BASE), + BASIC(event_deferred_cb_set_priority_, TT_FORK|TT_NEED_BASE), + BASIC(event_callback_init_, TT_FORK|TT_NEED_BASE), + BASIC(event_del_noblock, TT_FORK|TT_NEED_BASE), + BASIC(event_del_block, TT_FORK|TT_NEED_BASE), + BASIC(event_get_events, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), + BASIC(event_config_set_max_dispatch_interval, TT_FORK|TT_NEED_BASE), + BASIC(event_config_set_num_cpus_hint, TT_FORK|TT_NEED_BASE), + BASIC(event_base_stop_iocp_, TT_FORK|TT_NEED_BASE), ``` main_testcases[]的元素类型为struct testcase_t,而struct testcase_t的定义为: ```c /** A single test-case that you can run. */ struct testcase_t { const char *name; /**< An identifier for this case. */ testcase_fn fn; /**< The function to run to implement this case. */ unsigned long flags; /**< Bitfield of TT_* flags. */ const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ void *setup_data; /**< Extra data usable by setup function */ }; ``` 错误就出现在第二个元素testcase_fn fn,其类型定义为: ```c typedef void (*testcase_fn)(void *); ``` 也就是说,要求类型为void\*(void\*) 我们再来看看BASIC是什么,他是一个宏,定义如下,同时还需要注意,与他一同定义的LEGACY宏 ```c #define BASIC(name,flags) \ { #name, test_## name, flags, &basic_setup, NULL } #define LEGACY(name,flags) \ { #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup, \ test_## name } ``` 我们再回来看一开始报错的地方 ```c + BASIC(event_config_set_max_dispatch_interval, TT_FORK|TT_NEED_BASE), + BASIC(event_config_set_num_cpus_hint, TT_FORK|TT_NEED_BASE), ``` 也就是说,问题出在函数test_event_config_set_max_dispatch_interval和test_event_config_set_num_cpus_hint的类型不符合void\*(void\*)的要求,那我们来看看这两个函数的定义: ```c +static void +test_event_config_set_max_dispatch_interval(void) +{ + struct event_config *cfg = NULL; + struct timeval tv; + int max_dispatch_cbs = 100; + int min_priority = 2; + + evutil_timerclear(&tv); + tv.tv_sec = 3; + tv.tv_usec = 0; + + cfg = event_config_new(); + event_config_set_max_dispatch_interval(cfg, &tv, max_dispatch_cbs, min_priority); + + tt_assert(max_dispatch_cbs == cfg->max_dispatch_callbacks); + tt_assert(min_priority == cfg->limit_callbacks_after_prio); + tt_assert(3 == cfg->max_dispatch_interval.tv_sec); + tt_assert(0 == cfg->max_dispatch_interval.tv_usec); +end: + if (cfg) + event_config_free(cfg); +} + +static void +test_event_config_set_num_cpus_hint(void) +{ + struct event_config *cfg = NULL; + int n_cpus = 4; + + cfg = event_config_new(); + event_config_set_num_cpus_hint(cfg, 4); + tt_assert(4 == cfg->n_cpus_hint); +end: + if (cfg) + event_config_free(cfg); +} ``` 可见他们的类型是void(void) 除了这两个函数之外,其他BASIC宏传入的函数(没有被报错的)的类型例如下: ```c +static void +test_event_del_noblock(void *ptr) { + struct basic_test_data *data = ptr; + struct event_base *base = data->base; + struct timeval tv; + struct event ev; + int count = 0; + int res_del = 0; + + evutil_timerclear(&tv); + tv.tv_usec = 10000; + + event_assign(&ev, base, -1, EV_TIMEOUT|EV_PERSIST, + timeout_cb, &count); + event_add(&ev, &tv); + + res_del = event_del_noblock(&ev); + tt_int_op(res_del, ==, 0); +end: + ; +} + ``` 修改方法显然不能直接改参数要求,如果将void改为void*,那么凭空要求传入一个参数,显然不对,那么还有其他方法吗?我在上游社区没有发现类似的issue,然而,我们可以去找找看,对于void(void)类型的函数,上游社区是如何将其传入testcase的,我们大致看一部分: ```c struct testcase_t main_testcases[] = { /* Some converted-over tests */ { "methods", test_methods, TT_FORK, NULL, NULL }, { "version", test_version, 0, NULL, NULL }, BASIC(base_features, TT_FORK|TT_NO_LOGS), { "base_environ", test_base_environ, TT_FORK, NULL, NULL }, BASIC(event_base_new, TT_FORK|TT_NEED_SOCKETPAIR), BASIC(free_active_base, TT_FORK|TT_NEED_SOCKETPAIR), BASIC(manipulate_active_events, TT_FORK|TT_NEED_BASE), BASIC(event_new_selfarg, TT_FORK|TT_NEED_BASE), BASIC(event_assign_selfarg, TT_FORK|TT_NEED_BASE), BASIC(event_base_get_num_events, TT_FORK|TT_NEED_BASE), BASIC(event_base_get_max_events, TT_FORK|TT_NEED_BASE), BASIC(evmap_invalid_slots, TT_FORK|TT_NEED_BASE), BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS), BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_RETRIABLE), BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR), /* These are still using the old API */ LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE), { "persistent_timeout_jump", test_persistent_timeout_jump, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, { "persistent_active_timeout", test_persistent_active_timeout, TT_FORK|TT_NEED_BASE|TT_RETRIABLE, &basic_setup, NULL }, LEGACY(priorities, TT_FORK|TT_NEED_BASE), BASIC(priority_active_inversion, TT_FORK|TT_NEED_BASE), { "common_timeout", test_common_timeout, TT_FORK|TT_NEED_BASE|TT_RETRIABLE, &basic_setup, NULL }, /* These legacy tests may not all need all of these flags. */ LEGACY(simpleread, TT_ISOLATED), LEGACY(simpleread_multiple, TT_ISOLATED), LEGACY(simplewrite, TT_ISOLATED), { "simpleclose_rw", test_simpleclose_rw, TT_FORK, &basic_setup, NULL }, /* simpleclose */ { "simpleclose_close", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"close" }, { "simpleclose_shutdown", test_simpleclose, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, (void *)"shutdown" }, ``` 可见,除了BASIC,有时也用LEGACY,那么什么时候用BASIC,什么时候用LEGACY呢?本人查看了上文的所有testcase中的测试函数,发现BASIC用于传入void(void*),而LEGACY用于传入void(void),全部贴上来篇幅过长,因此此处只放一个例子: ```c LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE) ``` ```c static void test_persistent_timeout(void) { struct timeval tv; struct event ev; int count = 0; evutil_timerclear(&tv); tv.tv_usec = 10000; event_assign(&ev, global_base, -1, EV_TIMEOUT|EV_PERSIST, periodic_timeout_cb, &count); event_add(&ev, &tv); event_dispatch(); event_del(&ev); } ``` ## 2.2、问题总结及根因确认 [add-testcases-for-event.c-apis.patch](https://gitee.com/src-openeuler/libevent/blob/6fd712438bafd9eafdb3cf3b3e9d66913378b2a3/add-testcases-for-event.c-apis.patch)该patch试图增加对一些函数的testcase,对于void(void)类型的函数,正确的方法是调用LEGACY宏将函数加入测试行列,错误在于调用了BASIC宏(其用于void(void*)类型的函数) # 3、修改建议 把报错两处的BASIC改为LEGACY, 参考:[Fix function undeclared,incompatible pointer and parameter lack in 'add-testcases-for-event.c-apis.patch',support clang build · Pull Request !74 · src-openEuler/libevent - Gitee.com](https://gitee.com/src-openeuler/libevent/pulls/74)
此 Pull Request 需要通过一些审核项
类型
指派人员
状态
审查
openeuler-ci-bot
进行中
(0/1人)
测试
openeuler-ci-bot
进行中
(0/1人)
怎样手动合并此 Pull Request
git checkout master
git pull https://gitee.com/yuncang123/compiler-docs.git 6
git push origin master
评论
1
提交
1
文件
1
检查
代码问题
0
批量操作
展开设置
折叠设置
审查
Code Owner
审查人员
Noah
jvmboy
eastb233
eastb233
kuen
kuenking111_admin
cf-zhao
cf-zhao
编译小伙
li-yancheng
stubCode
stubCode
周磊
alexanderbill
openeuler-ci-bot
openeuler-ci-bot
未设置
最少人数
1
测试
Noah
jvmboy
eastb233
eastb233
kuen
kuenking111_admin
cf-zhao
cf-zhao
编译小伙
li-yancheng
stubCode
stubCode
周磊
alexanderbill
openeuler-ci-bot
openeuler-ci-bot
未设置
最少人数
1
优先级
不指定
严重
主要
次要
不重要
标签
openeuler-cla/yes
sig/Compiler
关联 Issue
未关联
Pull Request 合并后将关闭上述关联 Issue
里程碑
未关联里程碑
参与者
(2)
Cherry-pick 提交
Cherry-pick 可以将
特定提交(Commit)
从某个分支挑选并应用到另一个分支,实现快速集成特定更改,而无需合并整个分支。
请选择应用 Cherry-pick 提交 (Commit) 的目标分支
新建分支
当前账号不存在 Fork 仓库,建议 cherry-pick 到 Fork 仓库。
Fork 仓库
提交列表
Commit SHA
Commit Message
基于 Cherry-pick 后的分支发起 Pull Request
取消
Cherry-pick
1
https://gitee.com/openeuler/compiler-docs.git
git@gitee.com:openeuler/compiler-docs.git
openeuler
compiler-docs
compiler-docs
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册