Checking for list_empty doesn't stop until all entries have been removed, no matter their ref count.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/set.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index d1ea663..951c5ba 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -223,6 +223,7 @@ static HRESULT iterate_map(MapInstance *map, script_ctx_t *ctx, unsigned argc, j static HRESULT Map_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { + struct jsval_map_entry *entry, *entry2; MapInstance *map; HRESULT hres;
@@ -232,10 +233,8 @@ static HRESULT Map_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned
TRACE("%p\n", map);
- while(!list_empty(&map->entries)) { - struct jsval_map_entry *entry = LIST_ENTRY(list_head(&map->entries), struct jsval_map_entry, list_entry); + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &map->entries, struct jsval_map_entry, list_entry) delete_map_entry(map, entry); - }
if(r) *r = jsval_undefined(); return S_OK;
The current entry as well as the next entry may both be removed while iterating. Since we release the entry after the callback, obtaining the "next" entry would be using possibly freed memory. A safe iteration is required, but we need to obtain the next entry after the callback, not at the start of the loop, since it can be removed during it.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is a pre-existing problem. See for example 64-bit Debian VM results here: https://testbot.winehq.org/JobDetails.pl?Key=116313#k2202
dlls/jscript/set.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index 951c5ba..3173a55 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -183,7 +183,7 @@ static HRESULT set_map_entry(MapInstance *map, jsval_t key, jsval_t value, jsval
static HRESULT iterate_map(MapInstance *map, script_ctx_t *ctx, unsigned argc, jsval_t *argv, jsval_t *r) { - struct jsval_map_entry *entry; + struct jsval_map_entry *entry, *entry2; IDispatch *context_obj = NULL; HRESULT hres;
@@ -200,7 +200,7 @@ static HRESULT iterate_map(MapInstance *map, script_ctx_t *ctx, unsigned argc, j context_obj = get_object(argv[1]); }
- LIST_FOR_EACH_ENTRY(entry, &map->entries, struct jsval_map_entry, list_entry) { + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &map->entries, struct jsval_map_entry, list_entry) { jsval_t args[3], v; if(entry->deleted) continue; @@ -210,6 +210,9 @@ static HRESULT iterate_map(MapInstance *map, script_ctx_t *ctx, unsigned argc, j grab_map_entry(entry); hres = disp_call_value(ctx, get_object(argv[0]), context_obj, DISPATCH_METHOD, ARRAY_SIZE(args), args, &v); + + /* The callback may have possibly removed the next entry, so grab it here */ + entry2 = LIST_ENTRY(entry->list_entry.next, struct jsval_map_entry, list_entry); release_map_entry(entry); if(FAILED(hres)) return hres;