Make both method calls;
1. Consistently written with parameter names as per spec. 2. Fix parameter validation to be consistent with spec. 3. Fix szNameBuf parameter semantics as per spec. 4. Fix szNameBuf casing str search as per spec. 5. Factor out common code into TLB_ helpers vastly improves readability.
-- v8: dlls/oleaut32: Fix nonsensical memory access in ITypeLib2_Constructor_SLTG()
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index f421a76fe95..088fc06b119 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -1285,13 +1285,6 @@ static inline BSTR TLB_get_bstr(const TLBString *str) return str != NULL ? str->str : NULL; }
-static inline int TLB_str_memcmp(void *left, const TLBString *str, DWORD len) -{ - if(!str) - return 1; - return memcmp(left, str->str, len); -} - static inline const GUID *TLB_get_guidref(const TLBGuid *guid) { return guid != NULL ? &guid->guid : NULL; @@ -5026,26 +5019,26 @@ static HRESULT WINAPI ITypeLib2_fnIsName( { ITypeLibImpl *This = impl_from_ITypeLib2(iface); int tic; - UINT nNameBufLen = (lstrlenW(szNameBuf)+1)*sizeof(WCHAR), fdc, vrc; + UINT fdc, vrc;
TRACE("%p, %s, %#lx, %p.\n", iface, debugstr_w(szNameBuf), lHashVal, pfName);
*pfName=TRUE; for(tic = 0; tic < This->TypeInfoCount; ++tic){ ITypeInfoImpl *pTInfo = This->typeinfos[tic]; - if(!TLB_str_memcmp(szNameBuf, pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; + if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc]; int pc; - if(!TLB_str_memcmp(szNameBuf, pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; + if(!lstrcmpiW(TLB_get_bstr(pFInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; for(pc=0; pc < pFInfo->funcdesc.cParams; pc++){ - if(!TLB_str_memcmp(szNameBuf, pFInfo->pParamDesc[pc].Name, nNameBufLen)) + if(!lstrcmpiW(TLB_get_bstr(pFInfo->pParamDesc[pc].Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; } } for(vrc = 0; vrc < pTInfo->typeattr.cVars; ++vrc){ TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc]; - if(!TLB_str_memcmp(szNameBuf, pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; + if(!lstrcmpiW(TLB_get_bstr(pVInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; }
} @@ -5075,20 +5068,18 @@ static HRESULT WINAPI ITypeLib2_fnFindName( ITypeLibImpl *This = impl_from_ITypeLib2(iface); int tic; UINT count = 0; - UINT len;
TRACE("%p, %s %#lx, %p, %p, %p.\n", iface, debugstr_w(name), hash, ppTInfo, memid, found);
if ((!name && hash == 0) || !ppTInfo || !memid || !found) return E_INVALIDARG;
- len = (lstrlenW(name) + 1)*sizeof(WCHAR); for(tic = 0; count < *found && tic < This->TypeInfoCount; ++tic) { ITypeInfoImpl *pTInfo = This->typeinfos[tic]; TLBVarDesc *var; UINT fdc;
- if(!TLB_str_memcmp(name, pTInfo->Name, len)) { + if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), name)) { memid[count] = MEMBERID_NIL; goto ITypeLib2_fnFindName_exit; } @@ -5096,7 +5087,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName( for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { TLBFuncDesc *func = &pTInfo->funcdescs[fdc];
- if(!TLB_str_memcmp(name, func->Name, len)) { + if(!lstrcmpiW(TLB_get_bstr(func->Name), name)) { memid[count] = func->funcdesc.memid; goto ITypeLib2_fnFindName_exit; }
From: Edward O'Callaghan edward@antitrust.cc
Make the code a little more consistent to read and grep.
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 088fc06b119..496c87864ef 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -5028,17 +5028,17 @@ static HRESULT WINAPI ITypeLib2_fnIsName( ITypeInfoImpl *pTInfo = This->typeinfos[tic]; if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { - TLBFuncDesc *pFInfo = &pTInfo->funcdescs[fdc]; + TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc]; int pc; - if(!lstrcmpiW(TLB_get_bstr(pFInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; - for(pc=0; pc < pFInfo->funcdesc.cParams; pc++){ - if(!lstrcmpiW(TLB_get_bstr(pFInfo->pParamDesc[pc].Name), szNameBuf)) + if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; + for(pc=0; pc < pFDesc->funcdesc.cParams; pc++){ + if(!lstrcmpiW(TLB_get_bstr(pFDesc->pParamDesc[pc].Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; } } for(vrc = 0; vrc < pTInfo->typeattr.cVars; ++vrc){ - TLBVarDesc *pVInfo = &pTInfo->vardescs[vrc]; - if(!lstrcmpiW(TLB_get_bstr(pVInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; + TLBVarDesc *pVDesc = &pTInfo->vardescs[vrc]; + if(!lstrcmpiW(TLB_get_bstr(pVDesc->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; }
} @@ -5074,9 +5074,10 @@ static HRESULT WINAPI ITypeLib2_fnFindName( if ((!name && hash == 0) || !ppTInfo || !memid || !found) return E_INVALIDARG;
+ // TODO: factor out common impl with fnIsName(). for(tic = 0; count < *found && tic < This->TypeInfoCount; ++tic) { ITypeInfoImpl *pTInfo = This->typeinfos[tic]; - TLBVarDesc *var; + TLBVarDesc *pVDesc; UINT fdc;
if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), name)) { @@ -5085,17 +5086,17 @@ static HRESULT WINAPI ITypeLib2_fnFindName( }
for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { - TLBFuncDesc *func = &pTInfo->funcdescs[fdc]; + TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc];
- if(!lstrcmpiW(TLB_get_bstr(func->Name), name)) { - memid[count] = func->funcdesc.memid; + if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), name)) { + memid[count] = pFDesc->funcdesc.memid; goto ITypeLib2_fnFindName_exit; } }
- var = TLB_get_vardesc_by_name(pTInfo, name); - if (var) { - memid[count] = var->vardesc.memid; + pVDesc = TLB_get_vardesc_by_name(pTInfo, name); + if (pVDesc) { + memid[count] = pVDesc->vardesc.memid; goto ITypeLib2_fnFindName_exit; }
@@ -5598,14 +5599,14 @@ static void ITypeInfoImpl_Destroy(ITypeInfoImpl *This)
for(i = 0; i < This->typeattr.cVars; ++i) { - TLBVarDesc *pVInfo = &This->vardescs[i]; - if (pVInfo->vardesc_create) { - TLB_FreeVarDesc(pVInfo->vardesc_create); - } else if (pVInfo->vardesc.varkind == VAR_CONST) { - VariantClear(pVInfo->vardesc.lpvarValue); - free(pVInfo->vardesc.lpvarValue); + TLBVarDesc *pVDesc = &This->vardescs[i]; + if (pVDesc->vardesc_create) { + TLB_FreeVarDesc(pVDesc->vardesc_create); + } else if (pVDesc->vardesc.varkind == VAR_CONST) { + VariantClear(pVDesc->vardesc.lpvarValue); + free(pVDesc->vardesc.lpvarValue); } - TLB_FreeCustData(&pVInfo->custdata_list); + TLB_FreeCustData(&pVDesc->custdata_list); } free(This->vardescs);
From: Edward O'Callaghan edward@antitrust.cc
The methods fnFindName and fnIsName() are almost identical. Consistently match them where possible, paving the way for a common internal worker implementation.
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 496c87864ef..177a4b81e97 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -5019,27 +5019,34 @@ static HRESULT WINAPI ITypeLib2_fnIsName( { ITypeLibImpl *This = impl_from_ITypeLib2(iface); int tic; - UINT fdc, vrc;
TRACE("%p, %s, %#lx, %p.\n", iface, debugstr_w(szNameBuf), lHashVal, pfName);
*pfName=TRUE; for(tic = 0; tic < This->TypeInfoCount; ++tic){ ITypeInfoImpl *pTInfo = This->typeinfos[tic]; - if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; + TLBVarDesc *pVDesc; + UINT fdc; + + if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) + goto ITypeLib2_fnIsName_exit; + for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc]; int pc; - if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; + + if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) + goto ITypeLib2_fnIsName_exit; + for(pc=0; pc < pFDesc->funcdesc.cParams; pc++){ if(!lstrcmpiW(TLB_get_bstr(pFDesc->pParamDesc[pc].Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; } } - for(vrc = 0; vrc < pTInfo->typeattr.cVars; ++vrc){ - TLBVarDesc *pVDesc = &pTInfo->vardescs[vrc]; - if(!lstrcmpiW(TLB_get_bstr(pVDesc->Name), szNameBuf)) goto ITypeLib2_fnIsName_exit; - } + + pVDesc = TLB_get_vardesc_by_name(pTInfo, szNameBuf); + if (pVDesc) + goto ITypeLib2_fnIsName_exit;
} *pfName=FALSE;
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 177a4b81e97..00d8cdcc698 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -5066,8 +5066,8 @@ ITypeLib2_fnIsName_exit: */ static HRESULT WINAPI ITypeLib2_fnFindName( ITypeLib2 *iface, - LPOLESTR name, - ULONG hash, + LPOLESTR szNameBuf, + ULONG lHashVal, ITypeInfo **ppTInfo, MEMBERID *memid, UINT16 *found) @@ -5076,9 +5076,9 @@ static HRESULT WINAPI ITypeLib2_fnFindName( int tic; UINT count = 0;
- TRACE("%p, %s %#lx, %p, %p, %p.\n", iface, debugstr_w(name), hash, ppTInfo, memid, found); + TRACE("%p, %s %#lx, %p, %p, %p.\n", iface, debugstr_w(szNameBuf), lHashVal, ppTInfo, memid, found);
- if ((!name && hash == 0) || !ppTInfo || !memid || !found) + if ((!szNameBuf && !lHashVal) || !ppTInfo || !memid || !found) return E_INVALIDARG;
// TODO: factor out common impl with fnIsName(). @@ -5087,7 +5087,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName( TLBVarDesc *pVDesc; UINT fdc;
- if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), name)) { + if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) { memid[count] = MEMBERID_NIL; goto ITypeLib2_fnFindName_exit; } @@ -5095,13 +5095,13 @@ static HRESULT WINAPI ITypeLib2_fnFindName( for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc];
- if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), name)) { + if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) { memid[count] = pFDesc->funcdesc.memid; goto ITypeLib2_fnFindName_exit; } }
- pVDesc = TLB_get_vardesc_by_name(pTInfo, name); + pVDesc = TLB_get_vardesc_by_name(pTInfo, szNameBuf); if (pVDesc) { memid[count] = pVDesc->vardesc.memid; goto ITypeLib2_fnFindName_exit;
From: Edward O'Callaghan edward@antitrust.cc
Both the ::IsName() and ::FindName() methods should do case-insensitive searches however should fix up the szNameBuf param with any case diff upon a match.
Test-Fix-Spotted-by: Damien Zammit damien@zamaudio.com Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/tests/typelib.c | 2 -- dlls/oleaut32/typelib.c | 24 ++++++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/dlls/oleaut32/tests/typelib.c b/dlls/oleaut32/tests/typelib.c index 153964e17d5..f75102538fe 100644 --- a/dlls/oleaut32/tests/typelib.c +++ b/dlls/oleaut32/tests/typelib.c @@ -7743,11 +7743,9 @@ static void test_FindName(void) ti = (void*)0xdeadbeef; hr = ITypeLib_FindName(tl, buffW, 0, &ti, &memid, &c); ok(hr == S_OK, "got 0x%08lx\n", hr); -todo_wine { ok(memid == MEMBERID_NIL, "got %ld\n", memid); ok(!lstrcmpW(buffW, wszGUID), "got %s\n", wine_dbgstr_w(buffW)); ok(c == 1, "got %d\n", c); -} if (c == 1) ITypeInfo_Release(ti);
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 00d8cdcc698..6479c882933 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -1285,6 +1285,11 @@ static inline BSTR TLB_get_bstr(const TLBString *str) return str != NULL ? str->str : NULL; }
+static inline void TLB_set_bstr(LPOLESTR s, const TLBString *str) +{ + lstrcpyW(s, str->str); +} + static inline const GUID *TLB_get_guidref(const TLBGuid *guid) { return guid != NULL ? &guid->guid : NULL; @@ -5028,25 +5033,33 @@ static HRESULT WINAPI ITypeLib2_fnIsName( TLBVarDesc *pVDesc; UINT fdc;
- if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) + if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) { + TLB_set_bstr(szNameBuf, pTInfo->Name); goto ITypeLib2_fnIsName_exit; + }
for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc]; int pc;
- if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) + if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) { + TLB_set_bstr(szNameBuf, pFDesc->Name); goto ITypeLib2_fnIsName_exit; + }
for(pc=0; pc < pFDesc->funcdesc.cParams; pc++){ - if(!lstrcmpiW(TLB_get_bstr(pFDesc->pParamDesc[pc].Name), szNameBuf)) + if(!lstrcmpiW(TLB_get_bstr(pFDesc->pParamDesc[pc].Name), szNameBuf)) { + TLB_set_bstr(szNameBuf, pFDesc->pParamDesc[pc].Name); goto ITypeLib2_fnIsName_exit; + } } }
pVDesc = TLB_get_vardesc_by_name(pTInfo, szNameBuf); - if (pVDesc) + if (pVDesc) { + TLB_set_bstr(szNameBuf, pVDesc->Name); goto ITypeLib2_fnIsName_exit; + }
} *pfName=FALSE; @@ -5089,6 +5102,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName(
if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) { memid[count] = MEMBERID_NIL; + TLB_set_bstr(szNameBuf, pTInfo->Name); goto ITypeLib2_fnFindName_exit; }
@@ -5097,6 +5111,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName(
if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) { memid[count] = pFDesc->funcdesc.memid; + TLB_set_bstr(szNameBuf, pFDesc->Name); goto ITypeLib2_fnFindName_exit; } } @@ -5104,6 +5119,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName( pVDesc = TLB_get_vardesc_by_name(pTInfo, szNameBuf); if (pVDesc) { memid[count] = pVDesc->vardesc.memid; + TLB_set_bstr(szNameBuf, pVDesc->Name); goto ITypeLib2_fnFindName_exit; }
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 6479c882933..fee7151bb11 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -5027,6 +5027,9 @@ static HRESULT WINAPI ITypeLib2_fnIsName(
TRACE("%p, %s, %#lx, %p.\n", iface, debugstr_w(szNameBuf), lHashVal, pfName);
+ if ((!szNameBuf && !lHashVal) || !pfName) + return E_INVALIDARG; + *pfName=TRUE; for(tic = 0; tic < This->TypeInfoCount; ++tic){ ITypeInfoImpl *pTInfo = This->typeinfos[tic];
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 45 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index fee7151bb11..b86828c40c9 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -1677,6 +1677,18 @@ static inline TLBFuncDesc *TLB_get_funcdesc_by_memberid_invkind(ITypeInfoImpl *t return NULL; }
+static inline TLBFuncDesc *TLB_get_funcdesc_by_name(ITypeInfoImpl *typeinfo, const OLECHAR *name) +{ + for (int i = 0; i < typeinfo->typeattr.cFuncs; ++i) { + TLBFuncDesc *pFDesc = &typeinfo->funcdescs[i]; + + if (!lstrcmpiW(TLB_get_bstr(pFDesc->Name), name)) + return pFDesc; + } + + return NULL; +} + static inline TLBVarDesc *TLB_get_vardesc_by_memberid(ITypeInfoImpl *typeinfo, MEMBERID memid) { int i; @@ -5033,24 +5045,24 @@ static HRESULT WINAPI ITypeLib2_fnIsName( *pfName=TRUE; for(tic = 0; tic < This->TypeInfoCount; ++tic){ ITypeInfoImpl *pTInfo = This->typeinfos[tic]; + TLBFuncDesc *pFDesc; TLBVarDesc *pVDesc; - UINT fdc;
if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) { TLB_set_bstr(szNameBuf, pTInfo->Name); goto ITypeLib2_fnIsName_exit; }
- for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { - TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc]; - int pc; + pFDesc = TLB_get_funcdesc_by_name(pTInfo, szNameBuf); + if (pFDesc) { + TLB_set_bstr(szNameBuf, pFDesc->Name); + goto ITypeLib2_fnIsName_exit; + }
- if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) { - TLB_set_bstr(szNameBuf, pFDesc->Name); - goto ITypeLib2_fnIsName_exit; - } + for(UINT fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { + pFDesc = &pTInfo->funcdescs[fdc];
- for(pc=0; pc < pFDesc->funcdesc.cParams; pc++){ + for(int pc=0; pc < pFDesc->funcdesc.cParams; pc++){ if(!lstrcmpiW(TLB_get_bstr(pFDesc->pParamDesc[pc].Name), szNameBuf)) { TLB_set_bstr(szNameBuf, pFDesc->pParamDesc[pc].Name); goto ITypeLib2_fnIsName_exit; @@ -5100,8 +5112,8 @@ static HRESULT WINAPI ITypeLib2_fnFindName( // TODO: factor out common impl with fnIsName(). for(tic = 0; count < *found && tic < This->TypeInfoCount; ++tic) { ITypeInfoImpl *pTInfo = This->typeinfos[tic]; + TLBFuncDesc *pFDesc; TLBVarDesc *pVDesc; - UINT fdc;
if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) { memid[count] = MEMBERID_NIL; @@ -5109,14 +5121,11 @@ static HRESULT WINAPI ITypeLib2_fnFindName( goto ITypeLib2_fnFindName_exit; }
- for(fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { - TLBFuncDesc *pFDesc = &pTInfo->funcdescs[fdc]; - - if(!lstrcmpiW(TLB_get_bstr(pFDesc->Name), szNameBuf)) { - memid[count] = pFDesc->funcdesc.memid; - TLB_set_bstr(szNameBuf, pFDesc->Name); - goto ITypeLib2_fnFindName_exit; - } + pFDesc = TLB_get_funcdesc_by_name(pTInfo, szNameBuf); + if (pFDesc) { + memid[count] = pFDesc->funcdesc.memid; + TLB_set_bstr(szNameBuf, pFDesc->Name); + goto ITypeLib2_fnFindName_exit; }
pVDesc = TLB_get_vardesc_by_name(pTInfo, szNameBuf);
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index b86828c40c9..58ee7020521 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -1689,6 +1689,22 @@ static inline TLBFuncDesc *TLB_get_funcdesc_by_name(ITypeInfoImpl *typeinfo, con return NULL; }
+static inline TLBParDesc *TLB_get_funcparams_by_name(ITypeInfoImpl *typeinfo, const OLECHAR *name) +{ + for (int i = 0; i < typeinfo->typeattr.cFuncs; ++i) { + TLBFuncDesc *pFDesc = &typeinfo->funcdescs[i]; + + for (int pc = 0; pc < pFDesc->funcdesc.cParams; pc++){ + TLBParDesc *pPDesc = &pFDesc->pParamDesc[pc]; + + if (!lstrcmpiW(TLB_get_bstr(pPDesc->Name), name)) + return pPDesc; + } + } + + return NULL; +} + static inline TLBVarDesc *TLB_get_vardesc_by_memberid(ITypeInfoImpl *typeinfo, MEMBERID memid) { int i; @@ -5046,6 +5062,7 @@ static HRESULT WINAPI ITypeLib2_fnIsName( for(tic = 0; tic < This->TypeInfoCount; ++tic){ ITypeInfoImpl *pTInfo = This->typeinfos[tic]; TLBFuncDesc *pFDesc; + TLBParDesc *pPDesc; TLBVarDesc *pVDesc;
if(!lstrcmpiW(TLB_get_bstr(pTInfo->Name), szNameBuf)) { @@ -5059,15 +5076,10 @@ static HRESULT WINAPI ITypeLib2_fnIsName( goto ITypeLib2_fnIsName_exit; }
- for(UINT fdc = 0; fdc < pTInfo->typeattr.cFuncs; ++fdc) { - pFDesc = &pTInfo->funcdescs[fdc]; - - for(int pc=0; pc < pFDesc->funcdesc.cParams; pc++){ - if(!lstrcmpiW(TLB_get_bstr(pFDesc->pParamDesc[pc].Name), szNameBuf)) { - TLB_set_bstr(szNameBuf, pFDesc->pParamDesc[pc].Name); - goto ITypeLib2_fnIsName_exit; - } - } + pPDesc = TLB_get_funcparams_by_name(pTInfo, szNameBuf); + if (pPDesc) { + TLB_set_bstr(szNameBuf, pPDesc->Name); + goto ITypeLib2_fnIsName_exit; }
pVDesc = TLB_get_vardesc_by_name(pTInfo, szNameBuf);
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 58ee7020521..8ef9b82dd2e 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -5051,7 +5051,6 @@ static HRESULT WINAPI ITypeLib2_fnIsName( BOOL *pfName) { ITypeLibImpl *This = impl_from_ITypeLib2(iface); - int tic;
TRACE("%p, %s, %#lx, %p.\n", iface, debugstr_w(szNameBuf), lHashVal, pfName);
@@ -5059,7 +5058,7 @@ static HRESULT WINAPI ITypeLib2_fnIsName( return E_INVALIDARG;
*pfName=TRUE; - for(tic = 0; tic < This->TypeInfoCount; ++tic){ + for(int tic = 0; tic < This->TypeInfoCount; ++tic){ ITypeInfoImpl *pTInfo = This->typeinfos[tic]; TLBFuncDesc *pFDesc; TLBParDesc *pPDesc; @@ -5113,7 +5112,6 @@ static HRESULT WINAPI ITypeLib2_fnFindName( UINT16 *found) { ITypeLibImpl *This = impl_from_ITypeLib2(iface); - int tic; UINT count = 0;
TRACE("%p, %s %#lx, %p, %p, %p.\n", iface, debugstr_w(szNameBuf), lHashVal, ppTInfo, memid, found); @@ -5122,7 +5120,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName( return E_INVALIDARG;
// TODO: factor out common impl with fnIsName(). - for(tic = 0; count < *found && tic < This->TypeInfoCount; ++tic) { + for(int tic = 0; count < *found && tic < This->TypeInfoCount; ++tic) { ITypeInfoImpl *pTInfo = This->typeinfos[tic]; TLBFuncDesc *pFDesc; TLBVarDesc *pVDesc; @@ -5148,6 +5146,7 @@ static HRESULT WINAPI ITypeLib2_fnFindName( }
continue; + ITypeLib2_fnFindName_exit: ITypeInfo2_AddRef(&pTInfo->ITypeInfo2_iface); ppTInfo[count] = (ITypeInfo *)&pTInfo->ITypeInfo2_iface;
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 8ef9b82dd2e..6fcde6c94de 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -1072,7 +1072,7 @@ typedef struct tagITypeLibImpl TLBGuid *guid; LCID lcid; SYSKIND syskind; - int ptr_size; + ULONG ptr_size; WORD ver_major; WORD ver_minor; WORD libflags; @@ -1300,7 +1300,7 @@ static inline const GUID *TLB_get_guid_null(const TLBGuid *guid) return guid != NULL ? &guid->guid : &GUID_NULL; }
-static int get_ptr_size(SYSKIND syskind) +static ULONG get_ptr_size(SYSKIND syskind) { switch(syskind){ case SYS_WIN64:
From: Edward O'Callaghan edward@antitrust.cc
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 6fcde6c94de..fcf778553c7 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -5390,6 +5390,9 @@ static HRESULT WINAPI ITypeLibComp_fnBind(
for(i = 0; i < This->TypeInfoCount; ++i){ ITypeInfoImpl *pTypeInfo = This->typeinfos[i]; + ITypeComp *pSubTypeComp = &pTypeInfo->ITypeComp_iface; + HRESULT hr; + TRACE("testing %s\n", debugstr_w(TLB_get_bstr(pTypeInfo->Name)));
/* FIXME: check wFlags here? */ @@ -5401,18 +5404,11 @@ static HRESULT WINAPI ITypeLibComp_fnBind( if (pTypeInfo->Name && !wcscmp(pTypeInfo->Name->str, szName)) { *pDescKind = DESCKIND_TYPECOMP; - pBindPtr->lptcomp = &pTypeInfo->ITypeComp_iface; + pBindPtr->lptcomp = pSubTypeComp; ITypeComp_AddRef(pBindPtr->lptcomp); TRACE("module or enum: %s\n", debugstr_w(szName)); return S_OK; } - } - - if ((pTypeInfo->typeattr.typekind == TKIND_MODULE) || - (pTypeInfo->typeattr.typekind == TKIND_ENUM)) - { - ITypeComp *pSubTypeComp = &pTypeInfo->ITypeComp_iface; - HRESULT hr;
hr = ITypeComp_Bind(pSubTypeComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr); if (SUCCEEDED(hr) && (*pDescKind != DESCKIND_NONE)) @@ -5427,8 +5423,6 @@ static HRESULT WINAPI ITypeLibComp_fnBind( if ((pTypeInfo->typeattr.typekind == TKIND_COCLASS) && (pTypeInfo->typeattr.wTypeFlags & TYPEFLAG_FAPPOBJECT)) { - ITypeComp *pSubTypeComp = &pTypeInfo->ITypeComp_iface; - HRESULT hr; ITypeInfo *subtypeinfo; BINDPTR subbindptr; DESCKIND subdesckind;
From: Edward O'Callaghan edward@antitrust.cc
Index the pointer array in ITypeLib2_Constructor_SLTG() over using pointer arithmetic. Fix unvalidated calloc() calls while here.
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 64 ++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index fcf778553c7..d91977723cd 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -4417,7 +4417,6 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) char *pNameTable, *ptr; int i; DWORD len, order; - ITypeInfoImpl **ppTypeInfoImpl;
TRACE_(typelib)("%p, TLB length = %ld\n", pLib, dwTLBLength);
@@ -4482,7 +4481,10 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) /* And now TypeInfoCount of SLTG_OtherTypeInfo */
pOtherTypeInfoBlks = calloc(pTypeLibImpl->TypeInfoCount, sizeof(*pOtherTypeInfoBlks)); - + if (!pOtherTypeInfoBlks) { + free(pTypeLibImpl); + return NULL; + }
ptr = (char*)pLibBlk + len;
@@ -4561,7 +4563,11 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) them in the order in which they are in the file */
pTypeLibImpl->typeinfos = calloc(pTypeLibImpl->TypeInfoCount, sizeof(ITypeInfoImpl*)); - ppTypeInfoImpl = pTypeLibImpl->typeinfos; + if (!pTypeLibImpl->typeinfos) { + free(pTypeLibImpl); + free(pOtherTypeInfoBlks); + return NULL; + }
for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0; pBlkEntry[order].next != 0; @@ -4570,6 +4576,7 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) SLTG_TypeInfoHeader *pTIHeader; SLTG_TypeInfoTail *pTITail; SLTG_MemberHeader *pMemHeader; + ITypeInfoImpl *pTypeInfoImpl = pTypeLibImpl->typeinfos[i];
if(strcmp(pBlkEntry[order].index_string + (char*)pMagic, pOtherTypeInfoBlks[i].index_name)) { FIXME_(typelib)("Index strings don't match\n"); @@ -4587,20 +4594,20 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) "pTIHeader->res16 = %lx, pTIHeader->res1e = %lx\n", pTIHeader->res06, pTIHeader->res0e, pTIHeader->res16, pTIHeader->res1e);
- *ppTypeInfoImpl = ITypeInfoImpl_Constructor(); - (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl; - (*ppTypeInfoImpl)->index = i; - (*ppTypeInfoImpl)->Name = SLTG_ReadName(pNameTable, pOtherTypeInfoBlks[i].name_offs, pTypeLibImpl); - (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext; - (*ppTypeInfoImpl)->guid = TLB_append_guid(&pTypeLibImpl->guid_list, &pOtherTypeInfoBlks[i].uuid, 2); - (*ppTypeInfoImpl)->typeattr.typekind = pTIHeader->typekind; - (*ppTypeInfoImpl)->typeattr.wMajorVerNum = pTIHeader->major_version; - (*ppTypeInfoImpl)->typeattr.wMinorVerNum = pTIHeader->minor_version; - (*ppTypeInfoImpl)->typeattr.wTypeFlags = + pTypeInfoImpl = ITypeInfoImpl_Constructor(); + pTypeInfoImpl->pTypeLib = pTypeLibImpl; + pTypeInfoImpl->index = i; + pTypeInfoImpl->Name = SLTG_ReadName(pNameTable, pOtherTypeInfoBlks[i].name_offs, pTypeLibImpl); + pTypeInfoImpl->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext; + pTypeInfoImpl->guid = TLB_append_guid(&pTypeLibImpl->guid_list, &pOtherTypeInfoBlks[i].uuid, 2); + pTypeInfoImpl->typeattr.typekind = pTIHeader->typekind; + pTypeInfoImpl->typeattr.wMajorVerNum = pTIHeader->major_version; + pTypeInfoImpl->typeattr.wMinorVerNum = pTIHeader->minor_version; + pTypeInfoImpl->typeattr.wTypeFlags = (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5);
- if((*ppTypeInfoImpl)->typeattr.wTypeFlags & TYPEFLAG_FDUAL) - (*ppTypeInfoImpl)->typeattr.typekind = TKIND_DISPATCH; + if(pTypeInfoImpl->typeattr.wTypeFlags & TYPEFLAG_FDUAL) + pTypeInfoImpl->typeattr.typekind = TKIND_DISPATCH;
if((pTIHeader->typeflags1 & 7) != 2) FIXME_(typelib)("typeflags1 = %02x\n", pTIHeader->typeflags1); @@ -4608,52 +4615,52 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) FIXME_(typelib)("typeflags3 = %02x\n", pTIHeader->typeflags3);
TRACE_(typelib)("TypeInfo %s of kind %s guid %s typeflags %04x\n", - debugstr_w(TLB_get_bstr((*ppTypeInfoImpl)->Name)), + debugstr_w(TLB_get_bstr(pTypeInfoImpl->Name)), typekind_desc[pTIHeader->typekind], - debugstr_guid(TLB_get_guidref((*ppTypeInfoImpl)->guid)), - (*ppTypeInfoImpl)->typeattr.wTypeFlags); + debugstr_guid(TLB_get_guidref(pTypeInfoImpl->guid)), + pTypeInfoImpl->typeattr.wTypeFlags);
pMemHeader = (SLTG_MemberHeader*)((char *)pBlk + pTIHeader->elem_table);
pTITail = (SLTG_TypeInfoTail*)((char *)(pMemHeader + 1) + pMemHeader->cbExtra);
- (*ppTypeInfoImpl)->typeattr.cbAlignment = pTITail->cbAlignment; - (*ppTypeInfoImpl)->typeattr.cbSizeInstance = pTITail->cbSizeInstance; - (*ppTypeInfoImpl)->typeattr.cbSizeVft = pTITail->cbSizeVft; + pTypeInfoImpl->typeattr.cbAlignment = pTITail->cbAlignment; + pTypeInfoImpl->typeattr.cbSizeInstance = pTITail->cbSizeInstance; + pTypeInfoImpl->typeattr.cbSizeVft = pTITail->cbSizeVft;
switch(pTIHeader->typekind) { case TKIND_ENUM: - SLTG_ProcessEnum((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessEnum((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
case TKIND_RECORD: - SLTG_ProcessRecord((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessRecord((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
case TKIND_INTERFACE: - SLTG_ProcessInterface((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessInterface((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
case TKIND_COCLASS: - SLTG_ProcessCoClass((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessCoClass((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
case TKIND_ALIAS: - SLTG_ProcessAlias((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessAlias((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
case TKIND_DISPATCH: - SLTG_ProcessDispatch((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessDispatch((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
case TKIND_MODULE: - SLTG_ProcessModule((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable, + SLTG_ProcessModule((char *)(pMemHeader + 1), pTypeInfoImpl, pNameTable, pTIHeader, pTITail); break;
@@ -4680,7 +4687,6 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) X(32); X(34); #undef X - ++ppTypeInfoImpl; pBlk = (char*)pBlk + pBlkEntry[order].len; }
From: Edward O'Callaghan edward@antitrust.cc
Scope and index the pointer array in MSFT_DoVars() to avoid subtle pointer arithmetic.
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index d91977723cd..6c054d98576 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -2616,22 +2616,22 @@ static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs, static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count, int offset) { - int i; - MSFT_RefRecord refrec; - TLBImplType *pImpl; - TRACE_(typelib)("\n");
pTI->impltypes = TLBImplType_Alloc(count); - pImpl = pTI->impltypes; - for(i=0;i<count;i++){ - if(offset<0) break; /* paranoia */ + + for (int i = 0; i < count; i++) { + TLBImplType *pImpl = &pTI->impltypes[i]; + MSFT_RefRecord refrec; + + if (offset < 0) break; /* paranoia */ + MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset); pImpl->hRef = refrec.reftype; - pImpl->implflags=refrec.flags; + pImpl->implflags = refrec.flags; MSFT_CustData(pcx, refrec.oCustData, &pImpl->custdata_list); - offset=refrec.onext; - ++pImpl; + + offset = refrec.onext; } }
From: Edward O'Callaghan edward@antitrust.cc
Falling onto the other side of the branch results in a later strcmp() with a uninitialised pointer, make them NULL to be determinstic. Use calloc() to ensure the heap allocations are zeroed as well.
Signed-off-by: Edward O'Callaghan edward@antitrust.cc --- dlls/oleaut32/typelib.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 6c054d98576..a1f5edced0e 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -4497,23 +4497,23 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) w = *(WORD*)(ptr + 2); if(w != 0xffff) { len += w; - pOtherTypeInfoBlks[i].index_name = malloc(w + 1); + pOtherTypeInfoBlks[i].index_name = calloc(1, w + 1); memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w); - pOtherTypeInfoBlks[i].index_name[w] = '\0'; - } + } else + pOtherTypeInfoBlks[i].index_name = NULL; w = *(WORD*)(ptr + 4 + len); if(w != 0xffff) { TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w)); len += w; - pOtherTypeInfoBlks[i].other_name = malloc(w + 1); + pOtherTypeInfoBlks[i].other_name = calloc(1, w + 1); memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w); - pOtherTypeInfoBlks[i].other_name[w] = '\0'; - } + } else + pOtherTypeInfoBlks[i].other_name = NULL; pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6); pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8); extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len); if(extra) { - pOtherTypeInfoBlks[i].extra = malloc(extra); + pOtherTypeInfoBlks[i].extra = calloc(1, extra); memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra); len += extra; }
On Fri Feb 7 20:18:51 2025 +0000, Edward OC wrote:
Yes, three tests are fixed if you review.
absolute minimum
That is why commits have been split up to make things trivially clear.
But only renaming local variables is not something we normally do.
Except it isn't just renaming variables if you actually looked it over. No offense but this attitude to new contributions explains a lot about why this code is so horrifically inconsistent and in disrepair. There are multiple buffer overflows and deref of invalid ptr's, both of which controllable by the user and other subtle bugs. A few have been addressed here.
I have also been struggling with this broken DLL. The code quality is poor, for example malloc() is called instead of calloc() and memory is used partially uninitialised, just for starters.
Edward's cleanup patches above make it easier to follow what is going on.
FYI, there is also a huge general inefficiency with this DLL in particular that it uses an array instead of a hashmap to store typeinfos. It is not only an inefficiency but likely a blocker to a working implementation because some lookups don't have a name string to search, only a hash value. Edward has been very dedicated to help sort out what is needed to fix this. I suggest you take it on board that we are making headway to fixing this broken DLL before rejecting these patches outright, or it is likely new contributors like us will give up trying to contribute to this project before landing their first patch.
I am running the test suite now again on this branch to see if any tests fail, but last time I checked, it fixed three previously `todo_wine{}` tests.