[PATCH 2/2] jscript: Fix iterating through the map while entries are removed.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Jun 6 08:53:34 CDT 2022


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 at 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;
-- 
2.34.1




More information about the wine-devel mailing list