this repo has no description

Verify shadow stack before and after collect (#188)

- Also verify that the shadow stack points into the heap
- Scan from base of heap, not to/from space
- Use more expressive error
- When growing the heap, verify before swapping in new space

authored by bernsteinbear.com and committed by

GitHub 03e0ac22 86a617b7

+30 -11
+30 -11
runtime.c
··· 120 120 uintptr_t limit; 121 121 uintptr_t from_space; 122 122 uintptr_t to_space; 123 + uintptr_t base; 123 124 struct space space; 124 125 }; 125 126 ··· 158 159 abort(); 159 160 } 160 161 heap->space = space; 161 - heap->to_space = heap->hp = space.start; 162 + heap->base = heap->to_space = heap->hp = space.start; 162 163 heap->from_space = heap->limit = heap->hp + space.size / 2; 163 164 } 164 165 ··· 172 173 } 173 174 174 175 void flip(struct gc_heap* heap) { 175 - heap->hp = heap->from_space; 176 + heap->base = heap->hp = heap->from_space; 176 177 heap->from_space = heap->to_space; 177 178 heap->to_space = heap->hp; 178 179 heap->limit = heap->hp + heap->space.size / 2; ··· 213 214 } 214 215 215 216 static bool in_heap(struct gc_heap* heap, struct gc_obj* obj) { 216 - return (uword)obj >= heap->to_space && (uword)obj < heap->limit; 217 + return (uword)obj >= heap->base && (uword)obj < heap->hp; 217 218 } 218 219 219 220 void assert_in_heap(struct object** pointer, struct gc_heap* heap) { ··· 224 225 if (in_const_heap(obj)) { 225 226 return; 226 227 } 227 - assert(in_heap(heap, obj)); 228 + if (!in_heap(heap, obj)) { 229 + fprintf(stderr, "pointer %p not in heap [%p, %p)\n", obj, (void*)heap->to_space, 230 + (void*)heap->hp); 231 + abort(); 232 + } 228 233 } 229 234 230 235 static NEVER_INLINE void heap_verify(struct gc_heap* heap) { 231 - uintptr_t scan = heap->to_space; 236 + assert(heap->base <= heap->hp); 237 + trace_roots(heap, assert_in_heap); 238 + uintptr_t scan = heap->base; 232 239 while (scan < heap->hp) { 233 240 struct gc_obj* obj = (struct gc_obj*)scan; 234 241 scan += align_size(trace_heap_object(obj, heap, assert_in_heap)); 235 242 } 236 243 } 237 244 238 - void collect(struct gc_heap* heap) { 239 - #ifndef NDEBUG 240 - heap_verify(heap); 241 - #endif 245 + void collect_no_verify(struct gc_heap* heap) { 242 246 flip(heap); 243 247 uintptr_t scan = heap->hp; 244 248 trace_roots(heap, visit_field); ··· 248 252 } 249 253 // TODO(max): If we have < 25% heap utilization, shrink the heap 250 254 #ifndef NDEBUG 251 - heap_verify(heap); 252 255 // Zero out the rest of the heap for debugging 253 256 memset((void*)scan, 0, heap->limit - scan); 254 257 #endif 255 258 } 256 259 260 + void collect(struct gc_heap* heap) { 261 + #ifndef NDEBUG 262 + heap_verify(heap); 263 + #endif 264 + collect_no_verify(heap); 265 + #ifndef NDEBUG 266 + heap_verify(heap); 267 + #endif 268 + } 269 + 257 270 #if defined(__builtin_expect) 258 271 #define LIKELY(x) __builtin_expect(!!(x), 1) 259 272 #define UNLIKELY(x) __builtin_expect(!!(x), 0) ··· 267 280 static NEVER_INLINE void heap_grow(struct gc_heap* heap) { 268 281 struct space old_space = heap->space; 269 282 struct space new_space = make_space(old_space.size * 2); 283 + #ifndef NDEBUG 284 + heap_verify(heap); 285 + #endif 270 286 init_heap(heap, new_space); 271 - collect(heap); 287 + collect_no_verify(heap); 288 + #ifndef NDEBUG 289 + heap_verify(heap); 290 + #endif 272 291 destroy_space(old_space); 273 292 } 274 293 #endif