Fix potential integer overflow in GC_find_limit_* functions
authorIvan Maidanski <ivmai@mail.ru>
Tue, 15 Nov 2016 12:25:54 +0000 (15:25 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 15 Nov 2016 12:42:56 +0000 (15:42 +0300)
* os_dep.c [OPENBSD] (GC_find_limit_openbsd, GC_skip_hole_openbsd): Add
assertion for the minimum value of bound; increment result by pgsz only
if no overflow is guaranteed.
* os_dep.c [USE_PROC_FOR_LIBRARIES && THREADS || NEED_FIND_LIMIT]
(GC_find_limit_with_bound): Add assertion for the minimum/maximum value
of bound; increment/decrement result by MIN_PAGE_SIZE only if no
overflow/underflow is guaranteed.

os_dep.c

index 5a962c1..e8601b2 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -536,6 +536,8 @@ GC_INNER char * GC_get_maps(void)
 
     struct sigaction act;
     size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
+
+    GC_ASSERT((word)bound >= pgsz);
     GC_ASSERT(I_HOLD_LOCK());
 
     act.sa_handler = GC_fault_handler_openbsd;
@@ -547,11 +549,11 @@ GC_INNER char * GC_get_maps(void)
     if (sigsetjmp(GC_jmp_buf_openbsd, 1) == 0) {
       result = (ptr_t)((word)p & ~(pgsz-1));
       for (;;) {
-        result += pgsz;
-        if ((word)result >= (word)bound) {
+        if ((word)result >= (word)bound - pgsz) {
           result = bound;
           break;
         }
+        result += pgsz; /* no overflow expected */
         GC_noop1((word)(*result));
       }
     }
@@ -574,6 +576,8 @@ GC_INNER char * GC_get_maps(void)
 
     struct sigaction act;
     size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
+
+    GC_ASSERT((word)bound >= pgsz);
     GC_ASSERT(I_HOLD_LOCK());
 
     act.sa_handler = GC_fault_handler_openbsd;
@@ -586,10 +590,10 @@ GC_INNER char * GC_get_maps(void)
     result = (ptr_t)((word)p & ~(pgsz-1));
     if (sigsetjmp(GC_jmp_buf_openbsd, 1) != 0 || firstpass) {
       firstpass = 0;
-      result += pgsz;
-      if ((word)result >= (word)bound) {
+      if ((word)result >= (word)bound - pgsz) {
         result = bound;
       } else {
+        result += pgsz; /* no overflow expected */
         GC_noop1((word)(*result));
       }
     }
@@ -942,6 +946,8 @@ GC_INNER size_t GC_page_size = 0;
                 /* static since it's only called with the               */
                 /* allocation lock held.                                */
 
+        GC_ASSERT(up ? (word)bound >= MIN_PAGE_SIZE
+                     : (word)bound <= ~(word)MIN_PAGE_SIZE);
         GC_ASSERT(I_HOLD_LOCK());
         GC_setup_temporary_fault_handler();
         if (SETJMP(GC_jmp_buf) == 0) {
@@ -949,14 +955,13 @@ GC_INNER size_t GC_page_size = 0;
                               & ~(MIN_PAGE_SIZE-1));
             for (;;) {
                 if (up) {
-                    result += MIN_PAGE_SIZE;
-                    if ((word)result >= (word)bound) {
+                    if ((word)result >= (word)bound - MIN_PAGE_SIZE) {
                       result = bound;
                       break;
                     }
+                    result += MIN_PAGE_SIZE; /* no overflow expected */
                 } else {
-                    result -= MIN_PAGE_SIZE;
-                    if ((word)result <= (word)bound) {
+                    if ((word)result <= (word)bound + MIN_PAGE_SIZE) {
                       result = bound - MIN_PAGE_SIZE;
                                         /* This is to compensate        */
                                         /* further result increment (we */
@@ -965,6 +970,7 @@ GC_INNER size_t GC_page_size = 0;
                                         /* by setjmp otherwise).        */
                       break;
                     }
+                    result -= MIN_PAGE_SIZE; /* no underflow expected */
                 }
                 GC_noop1((word)(*result));
             }