[Python-checkins] r42625 - python/branches/tim-obmalloc/Objects/obmalloc.c

tim.peters python-checkins at python.org
Mon Feb 27 23:43:35 CET 2006


Author: tim.peters
Date: Mon Feb 27 23:43:34 2006
New Revision: 42625

Modified:
   python/branches/tim-obmalloc/Objects/obmalloc.c
Log:
new_arena():  Catch possible (albeit very unlikely) overflows
when expanding the vector of arena descriptors.  Started adding
XXX to parts of the code I don't understand.


Modified: python/branches/tim-obmalloc/Objects/obmalloc.c
==============================================================================
--- python/branches/tim-obmalloc/Objects/obmalloc.c	(original)
+++ python/branches/tim-obmalloc/Objects/obmalloc.c	Mon Feb 27 23:43:34 2006
@@ -248,7 +248,7 @@
 
 /* Record keeping for arenas. */
 struct arena_object {
-	/* The address of the 256k arena block, as returned by malloc. */
+	/* The address of the arena, as returned by malloc. */
 	uptr address;
 
 	/* Pool-aligned pointer to the next pool to be carved off. */
@@ -265,11 +265,11 @@
 	/* Singly-linked list of available pools. */
 	struct pool_header* freepools;
 
-	/* Doubly-linked list of arena objects. */
-	struct arena_object* nextarena;
-	/* Used to locate arenas with pools available, and to locate unused
+	/* Doubly-linked list of arena objects.
+	 * Used to locate arenas with pools available, and to locate unused
 	 * arena objects.
 	 */
+	struct arena_object* nextarena;
 	struct arena_object* prevarena;
 };
 
@@ -428,10 +428,9 @@
  * available_arenas
  *
  * This is a singly linked list of arena_objects contained in the arenas array
- * which are currently not being used.  Objects are taken off the head of list
- * in new_arena(), and are pushed on the head of the list in PyObject_Free()
- * when the arena is empty.
- *
+ * which are currently not being used.  Objects are taken off the head of the
+ * list in new_arena(), and are pushed on the head of the list in
+ * PyObject_Free() when the arena is empty.
  *
  * partially_allocated_arenas
  *
@@ -441,12 +440,12 @@
  * (ascending order based on the nfreepools field).  This means that the next
  * allocation will come from a heavily used arena, which gives the nearly empty
  * arenas a chance to be returned to the system.  In my unscientific tests
- * this dramatically improved the amount of arenas that could be freed.
+ * this dramatically improved the number of arenas that could be freed.
  */
 
 /* Array of objects used to track chunks of memory (arenas). */
 static struct arena_object* arenas = NULL;
-/* Size of the arenas array. */
+/* Number of slots allocated in the `arenas` vector. */
 static uint maxarenas = 0;
 
 /* Singly linked list of available arena objects. */
@@ -455,11 +454,17 @@
 static struct arena_object* partially_allocated_arenas = NULL;
 
 /* How many arena objects do we initially allocate?
- * 16 = can allocate 4 MB before growing the array. */
+ * 16 = can allocate 16 arenas = 16 * ARENA_SIZE = 4MB before growing the
+ * `arenas` vector.
+ */
 #define INITIAL_ARENA_OBJECTS 16
 
-/* Allocate a new arena and its object.  If we run out of memory, return
- * NULL.
+/* Allocate a new arena.  If we run out of memory, return NULL.  Else
+ * allocate a new arena, and return the address of an arena_object
+ * descriptor describing the new arena.  The `prevarena` and `freepools`
+ * members of the arena_object are left as uninitialized trash.  XXX
+ * That last sentence isn't true right now (it's all zero filled, but don't
+ * know yet why we bother to do that).
  */
 static struct arena_object*
 new_arena(void)
@@ -475,13 +480,18 @@
 	if (available_arenas == NULL) {
 		uint i;
 		uint numarenas;
+		size_t nbytes;
 
-		/* Double the number of arena objects on each allocation. */
+		/* Double the number of arena objects on each allocation.
+		 * Note that it's possible for `numarenas` to overflow.
+		 */
 		numarenas = maxarenas ? maxarenas << 1 : INITIAL_ARENA_OBJECTS;
-
-		/* Resize the new arenas vector. */
-		arenaobj = realloc(arenas, numarenas * sizeof(*arenas));
-		/* Return NULL on allocation failure. */
+		if (numarenas <= maxarenas)
+			return NULL;	/* overflow */
+		nbytes = numarenas * sizeof(*arenas);
+		if (nbytes / sizeof(*arenas) != numarenas)
+			return NULL;	/* overflow */
+		arenaobj = realloc(arenas, nbytes);
 		if (arenaobj == NULL)
 			return NULL;
 		arenas = arenaobj;
@@ -496,16 +506,18 @@
 		assert(available_arenas == NULL);
 
 		/* Zero fill the new section of the array. */
+		/* XXX Why? */
 		memset(&(arenas[maxarenas]), 0,
-			sizeof(*arenas) * (numarenas - maxarenas));
+		       sizeof(*arenas) * (numarenas - maxarenas));
 
 		/* Put the new arenas on the available_arenas list. */
-		assert(arenas[numarenas-1].nextarena == NULL);
 		for (i = maxarenas; i < numarenas-1; ++i)
 			arenas[i].nextarena = &arenas[i+1];
-		available_arenas = &arenas[maxarenas];
+		/* The last new arenaobj still points to NULL. */
+		assert(arenas[numarenas-1].nextarena == NULL);
 
-		/* Update the global size variable. */
+		/* Update globals. */
+		available_arenas = &arenas[maxarenas];
 		maxarenas = numarenas;
 	}
 
@@ -517,6 +529,7 @@
 	assert(arenaobj->address == (uptr)NULL);
 
 	/* Fill the newly allocated or reused arena object with zeros. */
+	/* XXX Why? */
 	memset(arenaobj, 0, sizeof(*arenaobj));
 
 	arenaobj->address = (uptr)malloc(ARENA_SIZE);
@@ -531,15 +544,14 @@
 
 	/* base_address <- first pool-aligned address in the arena
 	   nfreepools <- number of whole pools that fit after alignment */
-	arenaobj->base_address = (block*) arenaobj->address;
+	arenaobj->base_address = (block*)arenaobj->address;
 	arenaobj->nfreepools = ARENA_SIZE / POOL_SIZE;
 	assert(POOL_SIZE * arenaobj->nfreepools == ARENA_SIZE);
-	excess = (uint) ((Py_uintptr_t)arenaobj->address & POOL_SIZE_MASK);
+	excess = (uint)((Py_uintptr_t)arenaobj->address & POOL_SIZE_MASK);
 	if (excess != 0) {
 		--arenaobj->nfreepools;
 		arenaobj->base_address += POOL_SIZE - excess;
 	}
-
 	arenaobj->ntotalpools = arenaobj->nfreepools;
 
 	return arenaobj;


More information about the Python-checkins mailing list