Bug 30551

Summary: Potential race in do_rehash
Product: [Mono] Runtime Reporter: Neale Ferguson <neale>
Component: GeneralAssignee: Bugzilla <bugzilla>
Status: RESOLVED FIXED    
Severity: normal CC: mono-bugs+mono, mono-bugs+runtime, vargaz
Priority: ---    
Version: 4.0.0   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Tags: Is this bug a regression?: ---
Last known good build:

Description Neale Ferguson 2015-05-28 14:47:31 UTC
When a hash table exceeds a threshold a rehash operation is triggered. At
the moment the new table is allocated and its address placed in the table
field of the structure. The do_rehash also then copies the entries from
the old table to the new. However, if there is another thread active that
is doing lookups then there is a window where the new table is still being
filled such that a lookup can fail. This is because the new table is made
active before it has been copied. This proposed patch will fill the new
table before swapping the old for the new table in the hash structure.

@@ -194,24 +196,24 @@ do_rehash (void *_data)
        Slot **table;
        /* printf ("Resizing diff=%d slots=%d\n", hash->in_use -
hash->last_rehash, hash->table_size); */
-       hash->last_rehash = hash->table_size;
        current_size = hash->table_size;
-       hash->table_size = data->new_size;
        /* printf ("New size: %d\n", hash->table_size); */
        table = hash->table;
-       hash->table = data->table;
        for (i = 0; i < current_size; i++){
                Slot *s, *next;
                for (s = table [i]; s != NULL; s = next){
-                       guint hashcode = ((*hash->hash_func) (s->key)) %
hash->table_size;
+                       guint hashcode = ((*hash->hash_func) (s->key)) %
data->new_size;
                        next = s->next;
-                       s->next = hash->table [hashcode];
-                       hash->table [hashcode] = s;
+                       s->next = data->table [hashcode];
+                       data->table [hashcode] = s;
                }
        }
+       hash->table_size = data->new_size;
+       hash->last_rehash = hash->table_size;
+       hash->table = data->table;
        return table;
}
Comment 1 Zoltan Varga 2015-06-04 16:51:48 UTC
This got fixed by 54e8010aadb4fe69d216a5835c7b01f6187f745e.