Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ecc6e6a

Browse files
committed
SF bug 1185883: PyObject_Realloc can't safely take over a block currently
managed by C, because it's possible for the block to be smaller than the new requested size, and at the end of allocated VM. Trying to copy over nbytes bytes to a Python small-object block can segfault then, and there's no portable way to avoid this (we would have to know how many bytes starting at p are addressable, and std C has no means to determine that). Bugfix candidate. Should be backported to 2.4, but I'm out of time.
1 parent 7d66b00 commit ecc6e6a

2 files changed

Lines changed: 40 additions & 35 deletions

File tree

Misc/NEWS

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ What's New in Python 2.5 alpha 1?
1212
Core and builtins
1313
-----------------
1414

15+
- SF bug #1185883: Python's small-object memory allocator took over
16+
a block managed by the platform C library whenever a realloc specified
17+
a small new size. However, there's no portable way to know then how
18+
much of the address space following the pointer is valid, so no
19+
portable way to copy data from the C-managed block into Python's
20+
small-object space without risking a memory fault. Python's small-object
21+
realloc now leaves such blocks under the control of the platform C
22+
realloc.
23+
1524
- SF bug #1232517: An overflow error was not detected properly when
1625
attempting to convert a large float to an int in os.utime().
1726

@@ -59,7 +68,7 @@ Core and builtins
5968
- Bug #1165306: instancemethod_new allowed the creation of a method
6069
with im_class == im_self == NULL, which caused a crash when called.
6170

62-
- Move exception finalisation later in the shutdown process - this
71+
- Move exception finalisation later in the shutdown process - this
6372
fixes the crash seen in bug #1165761
6473

6574
- Added two new builtins, any() and all().
@@ -74,15 +83,15 @@ Core and builtins
7483
- Bug #1155938: new style classes did not check that __init__() was
7584
returning None.
7685

77-
- Patch #802188: Report characters after line continuation character
86+
- Patch #802188: Report characters after line continuation character
7887
('\') with a specific error message.
7988

8089
- Bug #723201: Raise a TypeError for passing bad objects to 'L' format.
8190

8291
- Bug #1124295: the __name__ attribute of file objects was
8392
inadvertently made inaccessible in restricted mode.
8493

85-
- Bug #1074011: closing sys.std{out,err} now causes a flush() and
94+
- Bug #1074011: closing sys.std{out,err} now causes a flush() and
8695
an ferror() call.
8796

8897
- min() and max() now support key= arguments with the same meaning as in
@@ -103,7 +112,7 @@ Core and builtins
103112
Extension Modules
104113
-----------------
105114

106-
- Bug #1234979: For the argument of thread.Lock.acquire, the Windows
115+
- Bug #1234979: For the argument of thread.Lock.acquire, the Windows
107116
implemented treated all integer values except 1 as false.
108117

109118
- Bug #1194181: bz2.BZ2File didn't handle mode 'U' correctly.
@@ -128,7 +137,7 @@ Extension Modules
128137
- Patches #925152, #1118602: Avoid reading after the end of the buffer
129138
in pyexpat.GetInputContext.
130139

131-
- Patches #749830, #1144555: allow UNIX mmap size to default to current
140+
- Patches #749830, #1144555: allow UNIX mmap size to default to current
132141
file size.
133142

134143
- Added functional.partial(). See PEP309.
@@ -201,7 +210,7 @@ Library
201210
- Bug #1163325: Decimal infinities failed to hash. Attempting to
202211
hash a NaN raised an InvalidOperation instead of a TypeError.
203212

204-
- Patch #918101: Add tarfile open mode r|* for auto-detection of the
213+
- Patch #918101: Add tarfile open mode r|* for auto-detection of the
205214
stream compression; add, for symmetry reasons, r:* as a synonym of r.
206215

207216
- Patch #1043890: Add extractall method to tarfile.
@@ -212,7 +221,7 @@ Library
212221
- Patch #1103407: Properly deal with tarfile iterators when untarring
213222
symbolic links on Windows.
214223

215-
- Patch #645894: Use getrusage for computing the time consumption in
224+
- Patch #645894: Use getrusage for computing the time consumption in
216225
profile.py if available.
217226

218227
- Patch #1046831: Use get_python_version where appropriate in sysconfig.py.
@@ -250,7 +259,7 @@ Library
250259

251260
+ Dialects are now validated by the underlying C code, better
252261
reflecting it's capabilities, and improving it's compliance with
253-
PEP 305.
262+
PEP 305.
254263
+ Dialect parameter parsing has been re-implemented to improve error
255264
reporting.
256265
+ quotechar=None and quoting=QUOTE_NONE now work the way PEP 305

Objects/obmalloc.c

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@
139139
* getpagesize() call or deduced from various header files. To make
140140
* things simpler, we assume that it is 4K, which is OK for most systems.
141141
* It is probably better if this is the native page size, but it doesn't
142-
* have to be. In theory, if SYSTEM_PAGE_SIZE is larger than the native page
143-
* size, then `POOL_ADDR(p)->arenaindex' could rarely cause a segmentation
144-
* violation fault. 4K is apparently OK for all the platforms that python
142+
* have to be. In theory, if SYSTEM_PAGE_SIZE is larger than the native page
143+
* size, then `POOL_ADDR(p)->arenaindex' could rarely cause a segmentation
144+
* violation fault. 4K is apparently OK for all the platforms that python
145145
* currently targets.
146146
*/
147147
#define SYSTEM_PAGE_SIZE (4 * 1024)
@@ -841,30 +841,26 @@ PyObject_Realloc(void *p, size_t nbytes)
841841
}
842842
return bp;
843843
}
844-
/* We're not managing this block. */
845-
if (nbytes <= SMALL_REQUEST_THRESHOLD) {
846-
/* Take over this block -- ask for at least one byte so
847-
* we really do take it over (PyObject_Malloc(0) goes to
848-
* the system malloc).
849-
*/
850-
bp = PyObject_Malloc(nbytes ? nbytes : 1);
851-
if (bp != NULL) {
852-
memcpy(bp, p, nbytes);
853-
free(p);
854-
}
855-
else if (nbytes == 0) {
856-
/* Meet the doc's promise that nbytes==0 will
857-
* never return a NULL pointer when p isn't NULL.
858-
*/
859-
bp = p;
860-
}
861-
862-
}
863-
else {
864-
assert(nbytes != 0);
865-
bp = realloc(p, nbytes);
866-
}
867-
return bp;
844+
/* We're not managing this block. If nbytes <=
845+
* SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this
846+
* block. However, if we do, we need to copy the valid data from
847+
* the C-managed block to one of our blocks, and there's no portable
848+
* way to know how much of the memory space starting at p is valid.
849+
* As bug 1185883 pointed out the hard way, it's possible that the
850+
* C-managed block is "at the end" of allocated VM space, so that
851+
* a memory fault can occur if we try to copy nbytes bytes starting
852+
* at p. Instead we punt: let C continue to manage this block.
853+
*/
854+
if (nbytes)
855+
return realloc(p, nbytes);
856+
/* C doesn't define the result of realloc(p, 0) (it may or may not
857+
* return NULL then), but Python's docs promise that nbytes==0 never
858+
* returns NULL. We don't pass 0 to realloc(), to avoid that endcase
859+
* to begin with. Even then, we can't be sure that realloc() won't
860+
* return NULL.
861+
*/
862+
bp = realloc(p, 1);
863+
return bp ? bp : p;
868864
}
869865

870866
#else /* ! WITH_PYMALLOC */

0 commit comments

Comments
 (0)