summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-01-07 21:43:59 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-01-07 21:43:59 (GMT)
commitb7fb2e25fb826b5c654e5989183f1cca6b8ad450 (patch)
tree054b0a9c597e651c4cc182553d384c8d0638bb12
parent1122fa2eb4b0942e26ea12cfc0bd1e497411738b (diff)
downloadcpython-b7fb2e25fb826b5c654e5989183f1cca6b8ad450.zip
cpython-b7fb2e25fb826b5c654e5989183f1cca6b8ad450.tar.gz
cpython-b7fb2e25fb826b5c654e5989183f1cca6b8ad450.tar.bz2
Issue #8020: Avoid a crash where the small objects allocator would read
non-Python managed memory while it is being modified by another thread. Patch by Matt Bandy.
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/obmalloc.c28
3 files changed, 27 insertions, 6 deletions
diff --git a/Misc/ACKS b/Misc/ACKS
index fbc9326..6010ace 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -46,6 +46,7 @@ Stig Bakken
Greg Ball
Luigi Ballabio
Jeff Balogh
+Matt Bandy
Michael J. Barber
Chris Barker
Nick Barnes
diff --git a/Misc/NEWS b/Misc/NEWS
index 01c2542..d18b7e7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -36,6 +36,10 @@ Core and Builtins
Library
-------
+- Issue #8020: Avoid a crash where the small objects allocator would read
+ non-Python managed memory while it is being modified by another thread.
+ Patch by Matt Bandy.
+
- Issue #10827: Changed the rules for 2-digit years. The time.asctime
function will now format any year when ``time.accept2dyear`` is
false and will accept years >= 1000 otherwise. The year range
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index bbdc946..3916262 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -682,11 +682,19 @@ that this test determines whether an arbitrary address is controlled by
obmalloc in a small constant time, independent of the number of arenas
obmalloc controls. Since this test is needed at every entry point, it's
extremely desirable that it be this fast.
+
+Since Py_ADDRESS_IN_RANGE may be reading from memory which was not allocated
+by Python, it is important that (POOL)->arenaindex is read only once, as
+another thread may be concurrently modifying the value without holding the
+GIL. To accomplish this, the arenaindex_temp variable is used to store
+(POOL)->arenaindex for the duration of the Py_ADDRESS_IN_RANGE macro's
+execution. The caller of the macro is responsible for declaring this
+variable.
*/
#define Py_ADDRESS_IN_RANGE(P, POOL) \
- ((POOL)->arenaindex < maxarenas && \
- (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \
- arenas[(POOL)->arenaindex].address != 0)
+ ((arenaindex_temp = (POOL)->arenaindex) < maxarenas && \
+ (uptr)(P) - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && \
+ arenas[arenaindex_temp].address != 0)
/* This is only useful when running memory debuggers such as
@@ -945,6 +953,9 @@ PyObject_Free(void *p)
block *lastfree;
poolp next, prev;
uint size;
+#ifndef Py_USING_MEMORY_DEBUGGER
+ uint arenaindex_temp;
+#endif
if (p == NULL) /* free(NULL) has no effect */
return;
@@ -1167,6 +1178,9 @@ PyObject_Realloc(void *p, size_t nbytes)
void *bp;
poolp pool;
size_t size;
+#ifndef Py_USING_MEMORY_DEBUGGER
+ uint arenaindex_temp;
+#endif
if (p == NULL)
return PyObject_Malloc(nbytes);
@@ -1867,8 +1881,10 @@ _PyObject_DebugMallocStats(void)
int
Py_ADDRESS_IN_RANGE(void *P, poolp pool)
{
- return pool->arenaindex < maxarenas &&
- (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE &&
- arenas[pool->arenaindex].address != 0;
+ uint arenaindex_temp = pool->arenaindex;
+
+ return arenaindex_temp < maxarenas &&
+ (uptr)P - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE &&
+ arenas[arenaindex_temp].address != 0;
}
#endif