Kaynağa Gözat

[malloc] Check integrity of free list

Check the integrity of the free memory block list before and after any
modifications to the list.  We check that certain invariants are
preserved:

 - the list is a well-formed doubly linked list

 - all blocks are at least MIN_MEMBLOCK_SIZE

 - no block extends beyond the end of our address space

 - blocks remain sorted in ascending order of address

 - no blocks are adjacent (i.e. any adjacent blocks have been merged)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 yıl önce
ebeveyn
işleme
7871666740
1 değiştirilmiş dosya ile 59 ekleme ve 1 silme
  1. 59
    1
      src/core/malloc.c

+ 59
- 1
src/core/malloc.c Dosyayı Görüntüle

@@ -186,6 +186,42 @@ static inline void valgrind_make_blocks_noaccess ( void ) {
186 186
 	VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
187 187
 }
188 188
 
189
+/**
190
+ * Check integrity of the blocks in the free list
191
+ *
192
+ */
193
+static inline void check_blocks ( void ) {
194
+	struct memory_block *block;
195
+	struct memory_block *prev = NULL;
196
+
197
+	if ( ! ASSERTING )
198
+		return;
199
+
200
+	list_for_each_entry ( block, &free_blocks, list ) {
201
+
202
+		/* Check that list structure is intact */
203
+		list_check ( &block->list );
204
+
205
+		/* Check that block size is not too small */
206
+		assert ( block->size >= sizeof ( *block ) );
207
+		assert ( block->size >= MIN_MEMBLOCK_SIZE );
208
+
209
+		/* Check that block does not wrap beyond end of address space */
210
+		assert ( ( ( void * ) block + block->size ) >
211
+			 ( ( void * ) block ) );
212
+
213
+		/* Check that blocks remain in ascending order, and
214
+		 * that adjacent blocks have been merged.
215
+		 */
216
+		if ( prev ) {
217
+			assert ( ( ( void * ) block ) > ( ( void * ) prev ) );
218
+			assert ( ( ( void * ) block ) >
219
+				 ( ( ( void * ) prev ) + prev->size ) );
220
+		}
221
+		prev = block;
222
+	}
223
+}
224
+
189 225
 /**
190 226
  * Discard some cached data
191 227
  *
@@ -242,6 +278,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
242 278
 	assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
243 279
 
244 280
 	valgrind_make_blocks_defined();
281
+	check_blocks();
245 282
 
246 283
 	/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
247 284
 	 * calculate alignment mask.
@@ -314,6 +351,7 @@ void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
314 351
 	}
315 352
 
316 353
  done:
354
+	check_blocks();
317 355
 	valgrind_make_blocks_noaccess();
318 356
 	return ptr;
319 357
 }
@@ -338,6 +376,7 @@ void free_memblock ( void *ptr, size_t size ) {
338 376
 		return;
339 377
 
340 378
 	valgrind_make_blocks_defined();
379
+	check_blocks();
341 380
 
342 381
 	/* Round up size to match actual size that alloc_memblock()
343 382
 	 * would have used.
@@ -346,11 +385,29 @@ void free_memblock ( void *ptr, size_t size ) {
346 385
 	size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
347 386
 	freeing = ptr;
348 387
 	VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
349
-	freeing->size = size;
350 388
 	DBGC2 ( &heap, "Freeing [%p,%p)\n",
351 389
 		freeing, ( ( ( void * ) freeing ) + size ) );
352 390
 
391
+	/* Check that this block does not overlap the free list */
392
+	if ( ASSERTING ) {
393
+		list_for_each_entry ( block, &free_blocks, list ) {
394
+			if ( ( ( ( void * ) block ) <
395
+			       ( ( void * ) freeing + size ) ) &&
396
+			     ( ( void * ) freeing <
397
+			       ( ( void * ) block + block->size ) ) ) {
398
+				assert ( 0 );
399
+				DBGC ( &heap, "Double free of [%p,%p) "
400
+				       "overlapping [%p,%p) detected from %p\n",
401
+				       freeing,
402
+				       ( ( ( void * ) freeing ) + size ), block,
403
+				       ( ( void * ) block + block->size ),
404
+				       __builtin_return_address ( 0 ) );
405
+			}
406
+		}
407
+	}
408
+
353 409
 	/* Insert/merge into free list */
410
+	freeing->size = size;
354 411
 	list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
355 412
 		/* Calculate gaps before and after the "freeing" block */
356 413
 		gap_before = ( ( ( void * ) freeing ) - 
@@ -392,6 +449,7 @@ void free_memblock ( void *ptr, size_t size ) {
392 449
 	/* Update free memory counter */
393 450
 	freemem += size;
394 451
 
452
+	check_blocks();
395 453
 	valgrind_make_blocks_noaccess();
396 454
 }
397 455
 

Loading…
İptal
Kaydet