Fix out-of-memory handling in GC_toggleref_add
authorIvan Maidanski <ivmai@mail.ru>
Tue, 25 Aug 2015 07:19:05 +0000 (10:19 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 26 Aug 2015 20:20:45 +0000 (23:20 +0300)
* finalize.c (ensure_toggleref_capacity): Change return type from void
to GC_bool; return FALSE on allocation failure (or desired capacity
value overflow).
* finalize.c (GC_toggleref_add): Change return type from void to int.
* include/gc.h (GC_toggleref_add): Likewise.
* finalize.c (GC_toggleref_add): Return GC_NO_MEMORY if
ensure_toggleref_capacity failed, GC_SUCCESS otherwise (including the
case of no callback).

finalize.c
include/gc.h

index bbc9389..90d5f42 100644 (file)
@@ -372,28 +372,38 @@ void GC_toggleref_register_callback(int (*proccess_toggleref) (GC_PTR obj))
     GC_toggleref_callback = proccess_toggleref;
 }
 
-static void
+static GC_bool
 ensure_toggleref_capacity (int capacity)
 {
     if (!GC_toggleref_array) {
         GC_toggleref_array_capacity = 32;
         GC_toggleref_array = (GCToggleRef *) GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE (GC_toggleref_array_capacity * sizeof (GCToggleRef), NORMAL);
+        if (NULL == GC_toggleref_array)
+            return FALSE;
     }
-    if (GC_toggleref_array_size + capacity >= GC_toggleref_array_capacity) {
+    if ((unsigned)GC_toggleref_array_size + (unsigned)capacity
+            >= (unsigned)GC_toggleref_array_capacity) {
         GCToggleRef *tmp;
         int old_capacity = GC_toggleref_array_capacity;
-        while (GC_toggleref_array_capacity < GC_toggleref_array_size + capacity)
+        while ((unsigned)GC_toggleref_array_capacity
+                < (unsigned)GC_toggleref_array_size + (unsigned)capacity) {
             GC_toggleref_array_capacity *= 2;
+            if (GC_toggleref_array_capacity < 0) /* overflow */
+                return FALSE;
+        }
 
         tmp = (GCToggleRef *) GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE (GC_toggleref_array_capacity * sizeof (GCToggleRef), NORMAL);
+        if (NULL == tmp)
+            return FALSE;
         memcpy (tmp, GC_toggleref_array, GC_toggleref_array_size * sizeof (GCToggleRef));
 
         GC_INTERNAL_FREE(GC_toggleref_array);
         GC_toggleref_array = tmp;
     }
+    return TRUE;
 }
 
-void
+int
 GC_toggleref_add (GC_PTR object, int strong_ref)
 {
     DCL_LOCK_STATE;
@@ -402,13 +412,17 @@ GC_toggleref_add (GC_PTR object, int strong_ref)
     if (!GC_toggleref_callback)
         goto end;
 
-    ensure_toggleref_capacity (1);
+    if (!ensure_toggleref_capacity(1)) {
+        UNLOCK();
+        return GC_NO_MEMORY;
+    }
     GC_toggleref_array [GC_toggleref_array_size].strong_ref = strong_ref ? object : NULL;
     GC_toggleref_array [GC_toggleref_array_size].weak_ref = strong_ref ? (GC_hidden_pointer)NULL : GC_HIDE_POINTER (object);
     ++GC_toggleref_array_size;
 
 end:
     UNLOCK();
+    return GC_SUCCESS;
 }
 
 
index 04cf374..5a407cb 100644 (file)
@@ -1175,7 +1175,7 @@ GC_API int GC_CALL GC_unregister_long_link(void ** /* link */);
 
 /* toggleref support */
 GC_API void GC_toggleref_register_callback (int (*proccess_toggleref) (GC_PTR obj));
-GC_API void GC_toggleref_add (GC_PTR object, int strong_ref);
+GC_API int GC_toggleref_add (GC_PTR object, int strong_ref);
 
 /* Finalizer callback support.  Invoked by the collector (with  */
 /* the allocation lock held) for each unreachable object        */