hook: zero hooks before adding them

Clear the hook before adding it so that we are sure the removed
callback doesn't contain garbage and cause a crash on disconnect.

Mark the removed and priv fields as private. Make sure to add the
removed callback after adding the hook.

Fixes a crash in kwin
This commit is contained in:
Wim Taymans 2020-11-20 09:40:24 +01:00
parent 4d085816ef
commit fc2b0b20ad
3 changed files with 9 additions and 7 deletions

View file

@ -70,7 +70,8 @@ struct spa_interface {
struct spa_hook { struct spa_hook {
struct spa_list link; struct spa_list link;
struct spa_callbacks cb; struct spa_callbacks cb;
/** callback and data for the hook list */ /** callback and data for the hook list, private to the
* hook_list implementor */
void (*removed) (struct spa_hook *hook); void (*removed) (struct spa_hook *hook);
void *priv; void *priv;
}; };
@ -86,11 +87,12 @@ static inline bool spa_hook_list_is_empty(struct spa_hook_list *list)
return spa_list_is_empty(&list->list); return spa_list_is_empty(&list->list);
} }
/** Append a hook \memberof spa_hook */ /** Append a hook \memberof spa_hook. */
static inline void spa_hook_list_append(struct spa_hook_list *list, static inline void spa_hook_list_append(struct spa_hook_list *list,
struct spa_hook *hook, struct spa_hook *hook,
const void *funcs, void *data) const void *funcs, void *data)
{ {
spa_zero(*hook);
hook->cb = SPA_CALLBACKS_INIT(funcs, data); hook->cb = SPA_CALLBACKS_INIT(funcs, data);
spa_list_append(&list->list, &hook->link); spa_list_append(&list->list, &hook->link);
} }
@ -100,6 +102,7 @@ static inline void spa_hook_list_prepend(struct spa_hook_list *list,
struct spa_hook *hook, struct spa_hook *hook,
const void *funcs, void *data) const void *funcs, void *data)
{ {
spa_zero(*hook);
hook->cb = SPA_CALLBACKS_INIT(funcs, data); hook->cb = SPA_CALLBACKS_INIT(funcs, data);
spa_list_prepend(&list->list, &hook->link); spa_list_prepend(&list->list, &hook->link);
} }

View file

@ -291,12 +291,12 @@ static void test_hook(void)
spa_hook_list_init(&hl); spa_hook_list_init(&hl);
h = malloc(sizeof(struct spa_hook)); h = malloc(sizeof(struct spa_hook));
h->removed = hook_removed_cb;
spa_hook_list_append(&hl, h, &callbacks[1], &data); spa_hook_list_append(&hl, h, &callbacks[1], &data);
h->removed = hook_removed_cb;
h = malloc(sizeof(struct spa_hook)); h = malloc(sizeof(struct spa_hook));
h->removed = hook_removed_cb;
spa_hook_list_append(&hl, h, &callbacks[2], &data); spa_hook_list_append(&hl, h, &callbacks[2], &data);
h->removed = hook_removed_cb;
/* iterate with the simple API */ /* iterate with the simple API */
spa_hook_list_call_simple(&hl, struct my_hook, invoke, VERSION); spa_hook_list_call_simple(&hl, struct my_hook, invoke, VERSION);
@ -308,8 +308,8 @@ static void test_hook(void)
memset(&data, 0, sizeof(struct my_hook_data)); memset(&data, 0, sizeof(struct my_hook_data));
h = malloc(sizeof(struct spa_hook)); h = malloc(sizeof(struct spa_hook));
h->removed = hook_removed_cb;
spa_hook_list_prepend(&hl, h, &callbacks[0], &data); spa_hook_list_prepend(&hl, h, &callbacks[0], &data);
h->removed = hook_removed_cb;
/* call only the first hook - this should be callback_1 */ /* call only the first hook - this should be callback_1 */
count = spa_hook_list_call_once(&hl, struct my_hook, invoke, VERSION); count = spa_hook_list_call_once(&hl, struct my_hook, invoke, VERSION);
@ -323,8 +323,8 @@ static void test_hook(void)
/* add callback_4 - this is version 1, so it shouldn't be executed */ /* add callback_4 - this is version 1, so it shouldn't be executed */
h = malloc(sizeof(struct spa_hook)); h = malloc(sizeof(struct spa_hook));
h->removed = hook_removed_cb;
spa_hook_list_append(&hl, h, &callbacks[3], &data); spa_hook_list_append(&hl, h, &callbacks[3], &data);
h->removed = hook_removed_cb;
count = spa_hook_list_call(&hl, struct my_hook, invoke, VERSION); count = spa_hook_list_call(&hl, struct my_hook, invoke, VERSION);
spa_assert(count == 3); spa_assert(count == 3);

View file

@ -383,7 +383,6 @@ static void test_endpoint(void)
uint8_t buffer[1024]; uint8_t buffer[1024];
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, 1024); struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, 1024);
spa_zero(d);
d.loop = pw_main_loop_new(NULL); d.loop = pw_main_loop_new(NULL);
d.context = pw_context_new(pw_main_loop_get_loop(d.loop), NULL, 0); d.context = pw_context_new(pw_main_loop_get_loop(d.loop), NULL, 0);
spa_assert(d.context != NULL); spa_assert(d.context != NULL);