Skip to content

Commit 65cd21f

Browse files
authored
Merge branch 'main' into bisect_refleak
2 parents 2a82cdd + 95e271b commit 65cd21f

9 files changed

+55
-30
lines changed

Include/internal/pycore_frame.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,16 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame);
190190
void
191191
_PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear);
192192

193-
194193
static inline bool
195194
_PyThreadState_HasStackSpace(PyThreadState *tstate, int size)
196195
{
197-
return tstate->datastack_top + size < tstate->datastack_limit;
196+
assert(
197+
(tstate->datastack_top == NULL && tstate->datastack_limit == NULL)
198+
||
199+
(tstate->datastack_top != NULL && tstate->datastack_limit != NULL)
200+
);
201+
return tstate->datastack_top != NULL &&
202+
size < tstate->datastack_limit - tstate->datastack_top;
198203
}
199204

200205
extern _PyInterpreterFrame *

Lib/test/test_tracemalloc.py

+14
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,20 @@ def test_fork(self):
360360
else:
361361
support.wait_process(pid, exitcode=0)
362362

363+
def test_no_incomplete_frames(self):
364+
tracemalloc.stop()
365+
tracemalloc.start(8)
366+
367+
def f(x):
368+
def g():
369+
return x
370+
return g
371+
372+
obj = f(0).__closure__[0]
373+
traceback = tracemalloc.get_object_traceback(obj)
374+
self.assertIn("test_tracemalloc", traceback[-1].filename)
375+
self.assertNotIn("test_tracemalloc", traceback[-2].filename)
376+
363377

364378
class TestSnapshot(unittest.TestCase):
365379
maxDiff = 4000

Lib/test/test_typing.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -4391,19 +4391,19 @@ def blah():
43914391

43924392
blah()
43934393

4394-
@patch("typing._overload_registry",
4395-
defaultdict(lambda: defaultdict(dict)))
43964394
def test_overload_on_compiled_functions(self):
4397-
# The registry starts out empty:
4398-
self.assertEqual(typing._overload_registry, {})
4399-
4400-
# This should just not fail:
4401-
overload(sum)
4402-
overload(print)
4403-
4404-
# No overloads are recorded (but, it still has a side-effect):
4405-
self.assertEqual(typing.get_overloads(sum), [])
4406-
self.assertEqual(typing.get_overloads(print), [])
4395+
with patch("typing._overload_registry",
4396+
defaultdict(lambda: defaultdict(dict))):
4397+
# The registry starts out empty:
4398+
self.assertEqual(typing._overload_registry, {})
4399+
4400+
# This should just not fail:
4401+
overload(sum)
4402+
overload(print)
4403+
4404+
# No overloads are recorded (but, it still has a side-effect):
4405+
self.assertEqual(typing.get_overloads(sum), [])
4406+
self.assertEqual(typing.get_overloads(print), [])
44074407

44084408
def set_up_overloads(self):
44094409
def blah():
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an issue that could prevent :opcode:`LOAD_ATTR` from specializing
2+
properly when accessing properties.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove two cases of undefined behavoir, by adding NULL checks.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make sure that incomplete frames do not show up in tracemalloc traces.

Modules/_tracemalloc.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,13 @@ traceback_get_frames(traceback_t *traceback)
400400
}
401401

402402
_PyInterpreterFrame *pyframe = tstate->cframe->current_frame;
403-
for (; pyframe != NULL;) {
403+
for (;;) {
404+
while (pyframe && _PyFrame_IsIncomplete(pyframe)) {
405+
pyframe = pyframe->previous;
406+
}
407+
if (pyframe == NULL) {
408+
break;
409+
}
404410
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
405411
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
406412
assert(traceback->frames[traceback->nframe].filename != NULL);
@@ -410,8 +416,7 @@ traceback_get_frames(traceback_t *traceback)
410416
traceback->total_nframe++;
411417
}
412418

413-
_PyInterpreterFrame *back = pyframe->previous;
414-
pyframe = back;
419+
pyframe = pyframe->previous;
415420
}
416421
}
417422

Python/pystate.c

+5-8
Original file line numberDiff line numberDiff line change
@@ -2195,15 +2195,12 @@ _PyInterpreterFrame *
21952195
_PyThreadState_PushFrame(PyThreadState *tstate, size_t size)
21962196
{
21972197
assert(size < INT_MAX/sizeof(PyObject *));
2198-
PyObject **base = tstate->datastack_top;
2199-
PyObject **top = base + size;
2200-
if (top >= tstate->datastack_limit) {
2201-
base = push_chunk(tstate, (int)size);
2198+
if (_PyThreadState_HasStackSpace(tstate, (int)size)) {
2199+
_PyInterpreterFrame *res = (_PyInterpreterFrame *)tstate->datastack_top;
2200+
tstate->datastack_top += size;
2201+
return res;
22022202
}
2203-
else {
2204-
tstate->datastack_top = top;
2205-
}
2206-
return (_PyInterpreterFrame *)base;
2203+
return (_PyInterpreterFrame *)push_chunk(tstate, (int)size);
22072204
}
22082205

22092206
void

Python/specialize.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -775,8 +775,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
775775
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
776776
goto fail;
777777
}
778-
uint32_t version = function_check_args(fget, 1, LOAD_ATTR) &&
779-
function_get_version(fget, LOAD_ATTR);
778+
if (!function_check_args(fget, 1, LOAD_ATTR)) {
779+
goto fail;
780+
}
781+
uint32_t version = function_get_version(fget, LOAD_ATTR);
780782
if (version == 0) {
781783
goto fail;
782784
}
@@ -831,9 +833,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name)
831833
assert(type->tp_getattro == _Py_slot_tp_getattro);
832834
assert(Py_IS_TYPE(descr, &PyFunction_Type));
833835
_PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
834-
uint32_t func_version = function_check_args(descr, 2, LOAD_ATTR) &&
835-
function_get_version(descr, LOAD_ATTR);
836-
if (func_version == 0) {
836+
if (!function_check_args(descr, 2, LOAD_ATTR)) {
837837
goto fail;
838838
}
839839
/* borrowed */

0 commit comments

Comments
 (0)