diff --git a/py/gc.c b/py/gc.c
index bcf6cfcdda1cab17b67e829abf03179f5ebc5044..2930e9011071e890f8ebb9c47c3eb7f5ac4013ec 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -459,78 +459,91 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
         return NULL;
     }
 
-    void *ptr_out = NULL;
-    machine_uint_t ptr = (machine_uint_t)ptr_in;
-
+    // check for pure allocation
     if (ptr_in == NULL) {
         return gc_alloc(n_bytes, false);
     }
 
-    machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK) / BYTES_PER_BLOCK;
+    machine_uint_t ptr = (machine_uint_t)ptr_in;
+
+    // sanity check the ptr
+    if (!VERIFY_PTR(ptr)) {
+        return NULL;
+    }
+
     // get first block
     machine_uint_t block = BLOCK_FROM_PTR(ptr);
 
-    // Sabity checks
-    if (VERIFY_PTR(ptr) && ATB_GET_KIND(block) == AT_HEAD) {
+    // sanity check the ptr is pointing to the head of a block
+    if (ATB_GET_KIND(block) != AT_HEAD) {
+        return NULL;
+    }
 
-        byte block_type;
-        machine_uint_t n_free   = 0;
-        machine_uint_t n_blocks = 1; // counting HEAD block
-        machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
+    // compute number of new blocks that are requested
+    machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK) / BYTES_PER_BLOCK;
 
-        // get the number of consecutive tail blocks and
-        // the number of free blocks after last tail block
-        // stop if we reach (or are at) end of heap
-        while (block + n_blocks + n_free < max_block) {
-            if (n_blocks + n_free >= new_blocks) {
-                // stop as soon as we find enough blocks for n_bytes
-                break;
-            }
-            block_type = ATB_GET_KIND(block + n_blocks + n_free);
-            switch (block_type) {
-                case AT_FREE: n_free++; continue;
-                case AT_TAIL: n_blocks++; continue;
-                case AT_MARK: assert(0);
-            }
+    // get the number of consecutive tail blocks and
+    // the number of free blocks after last tail block
+    // stop if we reach (or are at) end of heap
+    machine_uint_t n_free   = 0;
+    machine_uint_t n_blocks = 1; // counting HEAD block
+    machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
+    while (block + n_blocks + n_free < max_block) {
+        if (n_blocks + n_free >= new_blocks) {
+            // stop as soon as we find enough blocks for n_bytes
             break;
         }
+        byte block_type = ATB_GET_KIND(block + n_blocks + n_free);
+        switch (block_type) {
+            case AT_FREE: n_free++; continue;
+            case AT_TAIL: n_blocks++; continue;
+            case AT_MARK: assert(0);
+        }
+        break;
+    }
+
+    // return original ptr if it already has the requested number of blocks
+    if (new_blocks == n_blocks) {
+        return ptr_in;
+    }
 
-        if (new_blocks == n_blocks) {
-            return ptr_in;
+    // check if we can shrink the allocated area
+    if (new_blocks < n_blocks) {
+        // free unneeded tail blocks
+        for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
+            ATB_ANY_TO_FREE(bl);
         }
+        return ptr_in;
+    }
 
-        if (new_blocks < n_blocks) {
-            // free unneeded tail blocks
-            for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
-                ATB_ANY_TO_FREE(bl);
-            }
-            return ptr_in;
-
-        // check if we can expand in place
-        } else if (new_blocks <= n_blocks + n_free) {
-            // mark few more blocks as used tail
-            for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
-                assert(ATB_GET_KIND(bl) == AT_FREE);
-                ATB_FREE_TO_TAIL(bl);
-            }
-            return ptr_in;
+    // check if we can expand in place
+    if (new_blocks <= n_blocks + n_free) {
+        // mark few more blocks as used tail
+        for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
+            assert(ATB_GET_KIND(bl) == AT_FREE);
+            ATB_FREE_TO_TAIL(bl);
+        }
+        return ptr_in;
+    }
 
-        // try to find a new contiguous chain
-        } else if ((ptr_out = gc_alloc(n_bytes,
+    // can't resize inplace; try to find a new contiguous chain
+    void *ptr_out = gc_alloc(n_bytes,
 #if MICROPY_ENABLE_FINALISER
-                        FTB_GET(block)
+        FTB_GET(block)
 #else
-                        false
+        false
 #endif
-                        )) != NULL) {
-            DEBUG_printf("gc_realloc: allocating new block\n");
-            memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
-            gc_free(ptr_in);
-            return ptr_out;
-        }
+    );
+
+    // check that the alloc succeeded
+    if (ptr_out == NULL) {
+        return NULL;
     }
 
-    return NULL;
+    DEBUG_printf("gc_realloc: allocating new block\n");
+    memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
+    gc_free(ptr_in);
+    return ptr_out;
 }
 #endif // Alternative gc_realloc impl