Quellcode durchsuchen

[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 vor 9 Jahren
Ursprung
Commit
7871666740
1 geänderte Dateien mit 59 neuen und 1 gelöschten Zeilen
  1. 59
    1
      src/core/malloc.c

+ 59
- 1
src/core/malloc.c Datei anzeigen

186
 	VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
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
  * Discard some cached data
226
  * Discard some cached data
191
  *
227
  *
242
 	assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
278
 	assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
243
 
279
 
244
 	valgrind_make_blocks_defined();
280
 	valgrind_make_blocks_defined();
281
+	check_blocks();
245
 
282
 
246
 	/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
283
 	/* Round up size to multiple of MIN_MEMBLOCK_SIZE and
247
 	 * calculate alignment mask.
284
 	 * calculate alignment mask.
314
 	}
351
 	}
315
 
352
 
316
  done:
353
  done:
354
+	check_blocks();
317
 	valgrind_make_blocks_noaccess();
355
 	valgrind_make_blocks_noaccess();
318
 	return ptr;
356
 	return ptr;
319
 }
357
 }
338
 		return;
376
 		return;
339
 
377
 
340
 	valgrind_make_blocks_defined();
378
 	valgrind_make_blocks_defined();
379
+	check_blocks();
341
 
380
 
342
 	/* Round up size to match actual size that alloc_memblock()
381
 	/* Round up size to match actual size that alloc_memblock()
343
 	 * would have used.
382
 	 * would have used.
346
 	size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
385
 	size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
347
 	freeing = ptr;
386
 	freeing = ptr;
348
 	VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
387
 	VALGRIND_MAKE_MEM_DEFINED ( freeing, sizeof ( *freeing ) );
349
-	freeing->size = size;
350
 	DBGC2 ( &heap, "Freeing [%p,%p)\n",
388
 	DBGC2 ( &heap, "Freeing [%p,%p)\n",
351
 		freeing, ( ( ( void * ) freeing ) + size ) );
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
 	/* Insert/merge into free list */
409
 	/* Insert/merge into free list */
410
+	freeing->size = size;
354
 	list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
411
 	list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
355
 		/* Calculate gaps before and after the "freeing" block */
412
 		/* Calculate gaps before and after the "freeing" block */
356
 		gap_before = ( ( ( void * ) freeing ) - 
413
 		gap_before = ( ( ( void * ) freeing ) - 
392
 	/* Update free memory counter */
449
 	/* Update free memory counter */
393
 	freemem += size;
450
 	freemem += size;
394
 
451
 
452
+	check_blocks();
395
 	valgrind_make_blocks_noaccess();
453
 	valgrind_make_blocks_noaccess();
396
 }
454
 }
397
 
455
 

Laden…
Abbrechen
Speichern