oleaut32: Don't free a string in SysFreeString if it's already in cache. (eterbug #8330)

Jacek Caban jacek на codeweavers.com
Ср Фев 13 21:57:21 MSK 2013


(cherry picked from commit ed9d78d2b96dd4c97a6402ff0d30ada47a352a6f)
---
 dlls/oleaut32/oleaut.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/dlls/oleaut32/oleaut.c b/dlls/oleaut32/oleaut.c
index 250a812..df9216b 100644
--- a/dlls/oleaut32/oleaut.c
+++ b/dlls/oleaut32/oleaut.c
@@ -90,14 +90,15 @@ typedef struct {
     } u;
 } bstr_t;
 
+#define BUCKET_SIZE 16
+#define BUCKET_BUFFER_SIZE 6
+
 typedef struct {
     unsigned short head;
     unsigned short cnt;
-    bstr_t *buf[6];
+    bstr_t *buf[BUCKET_BUFFER_SIZE];
 } bstr_cache_entry_t;
 
-#define BUCKET_SIZE 16
-
 #define ARENA_INUSE_FILLER     0x55
 #define ARENA_TAIL_FILLER      0xab
 #define ARENA_FREE_FILLER      0xfeeefeee
@@ -138,7 +139,7 @@ static bstr_t *alloc_bstr(size_t size)
 
         if(cache_entry) {
             ret = cache_entry->buf[cache_entry->head++];
-            cache_entry->head %= sizeof(cache_entry->buf)/sizeof(*cache_entry->buf);
+            cache_entry->head %= BUCKET_BUFFER_SIZE;
             cache_entry->cnt--;
         }
 
@@ -257,14 +258,26 @@ void WINAPI SysFreeString(BSTR str)
     bstr = bstr_from_str(str);
     cache_entry = get_cache_entry(bstr->size+sizeof(WCHAR));
     if(cache_entry) {
+        unsigned i;
+
         EnterCriticalSection(&cs_bstr_cache);
 
+        /* According to tests, freeing a string that's already in cache doesn't corrupt anything.
+         * For that to work we need to search the cache. */
+        for(i=0; i < cache_entry->cnt; i++) {
+            if(cache_entry->buf[(cache_entry->head+cache_entry->cnt) % BUCKET_BUFFER_SIZE] == bstr) {
+                WARN_(heap)("String already is in cache!\n");
+                LeaveCriticalSection(&cs_bstr_cache);
+                return;
+            }
+        }
+
         if(cache_entry->cnt < sizeof(cache_entry->buf)/sizeof(*cache_entry->buf)) {
-            cache_entry->buf[(cache_entry->head+cache_entry->cnt)%((sizeof(cache_entry->buf)/sizeof(*cache_entry->buf)))] = bstr;
+            cache_entry->buf[(cache_entry->head+cache_entry->cnt) % BUCKET_BUFFER_SIZE] = bstr;
             cache_entry->cnt++;
 
             if(WARN_ON(heap)) {
-                unsigned i, n = bstr_alloc_size(bstr->size) / sizeof(DWORD) - 1;
+                unsigned n = bstr_alloc_size(bstr->size) / sizeof(DWORD) - 1;
                 bstr->size = ARENA_FREE_FILLER;
                 for(i=0; i<n; i++)
                     bstr->u.dwptr[i] = ARENA_FREE_FILLER;
-- 
1.8.1.3


--Multipart=_Thu__14_Feb_2013_16_07_38_+0800_wruSMPkiI+4RXMO7--


Подробная информация о списке рассылки Wine-patches