diff --git a/dlls/oleaut32/oleaut.c b/dlls/oleaut32/oleaut.c index 07db9fff1fd..00e6daf2ec9 100644 --- a/dlls/oleaut32/oleaut.c +++ b/dlls/oleaut32/oleaut.c @@ -120,14 +120,27 @@ static inline bstr_t *bstr_from_str(BSTR str) return CONTAINING_RECORD(str, bstr_t, u.str); } -static inline bstr_cache_entry_t *get_cache_entry(size_t size) +static inline bstr_cache_entry_t *get_cache_entry_from_idx(unsigned cache_idx) { - unsigned cache_idx = FIELD_OFFSET(bstr_t, u.ptr[size+sizeof(WCHAR)-1])/BUCKET_SIZE; return bstr_cache_enabled && cache_idx < sizeof(bstr_cache)/sizeof(*bstr_cache) ? bstr_cache + cache_idx : NULL; } +static inline bstr_cache_entry_t *get_cache_entry(size_t size) +{ + unsigned cache_idx = FIELD_OFFSET(bstr_t, u.ptr[size+sizeof(WCHAR)-1])/BUCKET_SIZE; + return get_cache_entry_from_idx(cache_idx); +} + +static inline bstr_cache_entry_t *get_cache_entry_from_alloc_size(SIZE_T alloc_size) +{ + unsigned cache_idx; + if (alloc_size < BUCKET_SIZE) return NULL; + cache_idx = (alloc_size - BUCKET_SIZE) / BUCKET_SIZE; + return get_cache_entry_from_idx(cache_idx); +} + static bstr_t *alloc_bstr(size_t size) { bstr_cache_entry_t *cache_entry = get_cache_entry(size); @@ -234,6 +247,16 @@ BSTR WINAPI SysAllocString(LPCOLESTR str) return SysAllocStringLen(str, lstrlenW(str)); } +static inline IMalloc *get_malloc(void) +{ + static IMalloc *malloc; + + if (!malloc) + CoGetMalloc(1, &malloc); + + return malloc; +} + /****************************************************************************** * SysFreeString [OLEAUT32.6] * @@ -253,12 +276,19 @@ void WINAPI SysFreeString(BSTR str) { bstr_cache_entry_t *cache_entry; bstr_t *bstr; + IMalloc *malloc = get_malloc(); + SIZE_T alloc_size; if(!str) return; bstr = bstr_from_str(str); - cache_entry = get_cache_entry(bstr->size); + + alloc_size = IMalloc_GetSize(malloc, bstr); + if (alloc_size == ~0UL) + return; + + cache_entry = get_cache_entry_from_alloc_size(alloc_size); if(cache_entry) { unsigned i; diff --git a/dlls/oleaut32/tests/vartype.c b/dlls/oleaut32/tests/vartype.c index f7df9c58ea4..03f43ec456f 100644 --- a/dlls/oleaut32/tests/vartype.c +++ b/dlls/oleaut32/tests/vartype.c @@ -6369,9 +6369,15 @@ static void test_bstr_cache(void) ok(str == str2, "str != str2\n"); SysFreeString(str2); - /* Fill the bucket with cached entries. */ + /* Fill the bucket with cached entries. + We roll our own, to show that the cache doesn't use + the bstr length field to determine bucket allocation. */ for(i=0; i < sizeof(strs)/sizeof(*strs); i++) - strs[i] = SysAllocStringLen(NULL, 24); + { + DWORD_PTR *ptr = CoTaskMemAlloc(64); + ptr[0] = 0; + strs[i] = (BSTR)(ptr + 1); + } for(i=0; i < sizeof(strs)/sizeof(*strs); i++) SysFreeString(strs[i]);