[PATCH v2 4/4] vbscript: Store the necessary function and variable info in the script TypeInfo.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Oct 21 06:40:30 CDT 2019


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Functions and variables added during compilation are added to the code_list in
the script context. These lists are not freed even if the script is released
(by decreasing its state), but only if the entire script is destroyed. So we
need to handle it separately, becaues the TypeInfo can hold references to it.

release_vbscode_objects was added to preserve the behavior of releasing the
Dispatch objects at the time the script is released even if some TypeInfo
still exists that needs functions/variables info, in case any application
depends on this.

 dlls/vbscript/compile.c  | 10 ++++--
 dlls/vbscript/vbdisp.c   | 75 +++++++++++++++++++++++++++++++++++++++-
 dlls/vbscript/vbscript.c | 15 ++++++--
 dlls/vbscript/vbscript.h |  2 ++
 4 files changed, 96 insertions(+), 6 deletions(-)

diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index a9bf96e..ca1e619 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -1769,17 +1769,23 @@ static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
     return S_OK;
 }
 
+void release_vbscode_objects(vbscode_t *code)
+{
+    if(code->context)
+        IDispatch_Release(code->context);
+    code->context = NULL;
+}
+
 void release_vbscode(vbscode_t *code)
 {
     unsigned i;
 
     list_remove(&code->entry);
+    release_vbscode_objects(code);
 
     for(i=0; i < code->bstr_cnt; i++)
         SysFreeString(code->bstr_pool[i]);
 
-    if(code->context)
-        IDispatch_Release(code->context);
     heap_pool_free(&code->heap);
 
     heap_free(code->bstr_pool);
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index f787dd3..8f5599f 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -576,6 +576,14 @@ static BOOL update_ident_map(ScriptDisp *This)
 typedef struct {
     ITypeInfo ITypeInfo_iface;
     LONG ref;
+
+    UINT num_funcs;
+    UINT num_vars;
+    function_t **funcs;
+    dynamic_var_t **vars;
+
+    ScriptDisp *disp;
+    script_ctx_t *ctx;
 } ScriptTypeInfo;
 
 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
@@ -615,11 +623,22 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
 {
     ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
     LONG ref = InterlockedDecrement(&This->ref);
+    script_ctx_t *ctx = This->ctx;
 
     TRACE("(%p) ref=%d\n", This, ref);
 
     if (!ref)
     {
+        /* Release the code heaps if we are the last ones holding them */
+        if (!--ctx->code_refcnt)
+        {
+            while (!list_empty(&ctx->code_list))
+                release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
+            heap_free(ctx);
+        }
+        IDispatchEx_Release(&This->disp->IDispatchEx_iface);
+        heap_free(This->funcs);
+        heap_free(This->vars);
         heap_free(This);
     }
     return ref;
@@ -823,13 +842,67 @@ static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
 
 static HRESULT create_script_typeinfo(ScriptDisp *disp, ITypeInfo **typeinfo)
 {
+    UINT num_funcs = 0, num_vars = 0;
+    dynamic_var_t *var, **typevar;
+    function_t *func, **typefunc;
     ScriptTypeInfo *p;
+    BOOL add_const;
 
-    if (!(p = heap_alloc(sizeof(*p))))
+    if (!update_ident_map(disp) || !(p = heap_alloc(sizeof(*p))))
         return E_OUTOFMEMORY;
 
+    for (var = disp->ctx->global_vars; var; var = var->next)
+        num_vars++;
+
+    for (func = disp->ctx->global_funcs; func; func = func->next)
+        if (func->is_public)
+            num_funcs++;
+
     p->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
     p->ref = 1;
+    p->num_funcs = num_funcs;
+    p->num_vars = num_vars;
+    p->disp = disp;
+    p->ctx = disp->ctx;
+
+    p->funcs = heap_alloc(sizeof(*p->funcs) * num_funcs);
+    if (!p->funcs)
+    {
+        heap_free(p);
+        return E_OUTOFMEMORY;
+    }
+
+    p->vars = heap_alloc(sizeof(*p->vars) * num_vars);
+    if (!p->vars)
+    {
+        heap_free(p->funcs);
+        heap_free(p);
+        return E_OUTOFMEMORY;
+    }
+
+    /* Const variables must be placed after the other variables,
+       and the order for all reversed compared to the original. */
+    typevar = p->vars + num_vars - 1;
+    add_const = TRUE;
+    for (;;)
+    {
+        for (var = disp->ctx->global_vars; var; var = var->next)
+            if (var->is_const == add_const)
+                *typevar-- = var;
+
+        if (!add_const) break;
+        add_const = FALSE;
+    }
+
+    typefunc = p->funcs;
+    for (func = disp->ctx->global_funcs; func; func = func->next)
+        if (func->is_public)
+            *typefunc++ = func;
+
+    /* Since the variables and functions are stored in the code heaps,
+       increment the reference count for the existing code heaps. */
+    disp->ctx->code_refcnt++;
+    IDispatchEx_AddRef(&disp->IDispatchEx_iface);
 
     *typeinfo = &p->ITypeInfo_iface;
     return S_OK;
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c
index da5c3dd..27dfe83 100644
--- a/dlls/vbscript/vbscript.c
+++ b/dlls/vbscript/vbscript.c
@@ -183,11 +183,19 @@ static void release_script(script_ctx_t *ctx)
 
 static void destroy_script(script_ctx_t *ctx)
 {
-    while(!list_empty(&ctx->code_list))
-        release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
+    vbscode_t *code;
+
+    if (--ctx->code_refcnt)
+        LIST_FOR_EACH_ENTRY(code, &ctx->code_list, vbscode_t, entry)
+            release_vbscode_objects(code);
+    else
+        while (!list_empty(&ctx->code_list))
+            release_vbscode(LIST_ENTRY(list_head(&ctx->code_list), vbscode_t, entry));
 
     release_script(ctx);
-    heap_free(ctx);
+
+    if (!ctx->code_refcnt)
+        heap_free(ctx);
 }
 
 static void decrease_state(VBScript *This, SCRIPTSTATE state)
@@ -952,6 +960,7 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU
         return E_OUTOFMEMORY;
     }
 
+    ctx->code_refcnt = 1;
     ctx->safeopt = INTERFACE_USES_DISPEX;
     list_init(&ctx->objects);
     list_init(&ctx->code_list);
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 9933329..009e8de 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -174,6 +174,7 @@ typedef struct _dynamic_var_t {
 
 struct _script_ctx_t {
     IActiveScriptSite *site;
+    unsigned code_refcnt;
     LCID lcid;
 
     IInternetHostSecurityManager *secmgr;
@@ -349,6 +350,7 @@ struct _vbscode_t {
 };
 
 void release_vbscode(vbscode_t*) DECLSPEC_HIDDEN;
+void release_vbscode_objects(vbscode_t*) DECLSPEC_HIDDEN;
 HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,vbscode_t**) DECLSPEC_HIDDEN;
 HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,DWORD,class_desc_t**) DECLSPEC_HIDDEN;
 HRESULT exec_script(script_ctx_t*,BOOL,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*) DECLSPEC_HIDDEN;
-- 
2.21.0




More information about the wine-devel mailing list