emitter越界问题
我最近遇到一个问题,注册一个emitter事件后,在hadler里调用emitter_off解除该注册,并且在hadler中向同一个emitter分发其它事件;有检测出越界问题。故作出相关修改,详见 https://gitee.com/zengqianyin/awtk.git 25c332c6efb0364f12c4bd2cc932cba5bde65bff;看是否有必要合并至主分支中
你的意思是,在一个触发事件中删除当前触发的事件,会导致越界的问题吗?我看了你修改的代码和 emitter_dispatch 和 emitter_remove 的代码,还是没有很明白的你意思,或者你可以给我们一个测试代码,我们这边测试一下啊?
越界的情况比较复杂,不好编写demo,给你一段test代码,你应该能明白我代码中恢复上下文的目的了。 `#include "tkc/emitter.h"
#define EVT_TEST_1 0x2000 #define EVT_TEST_2 0x2001
emitter_t test_emitter; uint32_t event1 = 0; uint32_t event2 = 0; static ret_t __global_user_emitter_event_handler1(void *ctx, event_t *event) { printf("%p,%d\n",test_emitter.curr_iter,test_emitter.remove_curr_iter); emitter_off(&test_emitter,event1); printf("%p,%d\n",test_emitter.curr_iter,test_emitter.remove_curr_iter); emitter_dispatch_simple_event(&test_emitter, EVT_TEST_2); printf("%p,%d\n",test_emitter.curr_iter,test_emitter.remove_curr_iter); return RET_OK; } static ret_t __global_user_emitter_event_handler2(void *ctx, event_t *event) { return RET_OK; }
void test() { emitter_init(&test_emitter); event1 = emitter_on(&test_emitter, EVT_TEST_1, __global_user_emitter_event_handler1, NULL); event2 = emitter_on(&test_emitter, EVT_TEST_2, __global_user_emitter_event_handler2, NULL); emitter_dispatch_simple_event(&test_emitter, EVT_TEST_1); emitter_off(&test_emitter, event2); emitter_deinit(&test_emitter); }`
调换下顺序就有越界了 `#include "tkc/emitter.h"
#define EVT_TEST_1 0x2000 #define EVT_TEST_2 0x2001
emitter_t test_emitter; uint32_t event1 = 0; uint32_t event2 = 0; static ret_t __global_user_emitter_event_handler1(void *ctx, event_t *event) { printf("%p,%d\n",test_emitter.curr_iter,test_emitter.remove_curr_iter); emitter_dispatch_simple_event(&test_emitter, EVT_TEST_2); printf("%p,%d\n",test_emitter.curr_iter,test_emitter.remove_curr_iter); emitter_off(&test_emitter,event1); printf("%p,%d\n",test_emitter.curr_iter,test_emitter.remove_curr_iter); return RET_OK; } static ret_t __global_user_emitter_event_handler2(void *ctx, event_t *event) { return RET_OK; }
void test() { emitter_init(&test_emitter); event1 = emitter_on(&test_emitter, EVT_TEST_1, __global_user_emitter_event_handler1, NULL); event2 = emitter_on(&test_emitter, EVT_TEST_2, __global_user_emitter_event_handler2, NULL); emitter_dispatch_simple_event(&test_emitter, EVT_TEST_1); emitter_off(&test_emitter, event2); emitter_deinit(&test_emitter); }`
意思是上面的例子不会有问题,下面的会出现越界?我明天试一下
是的,下面的代码会越界
上下两份代码,应该只有 __global_user_emitter_event_handler1 函数中的逻辑不一样吧?我测试了一下,反而是第一个份代码是有问题(但这个问题不是越界,而是删除 EVT_TEST_2 的节点),而第二份代码好像没有问题吧?
第二份代码中的 emitter_dispatch_simple_event(&test_emitter, EVT_TEST_2); 虽然把 test_emitter.curr_iter 和 test_emitter.remove_curr_iter 变量都改为0,但是在下面的 emitter_off(&test_emitter,event1); 删除的时候,会直接删除的,也没有出现重复删除的情况,所以我没有看到第二份代码有问题。
但是我大概明白你加这两个临时变量的意图了。
你用valgrind跑一下就知道了。本来emitter_off的时候不应该删除的,而是应该在本次emitter_dispatch的单次循环结束后删除的。emitter_off删除之后,emitter_dispatch里的iter就是野指针了,iter->next就是一个未知值了
恩恩,是的,谢谢提出 bug,你提供的修复补丁应该也没有修复第一份代码的问题,我们这边研究一下怎样修改一下。