| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c86e7ff commit f8672b4
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ | |||
| 2 | 2 | import copy | |
| 3 | 3 | import pickle | |
| 4 | 4 | import dis | |
| 5 | + import sys | ||
| 5 | 6 | import threading | |
| 6 | 7 | import types | |
| 7 | 8 | import unittest | |
@@ -2171,6 +2172,39 @@ class MyList(list): pass | |||
| 2171 | 2172 | self.assert_no_opcode(my_list_append, "CALL_LIST_APPEND") | |
| 2172 | 2173 | self.assert_no_opcode(my_list_append, "CALL") | |
| 2173 | 2174 | ||
| 2175 | + @cpython_only | ||
| 2176 | + @requires_specialization | ||
| 2177 | + def test_call_list_append_memory_error(self): | ||
| 2178 | + # gh-151818: if CALL_LIST_APPEND fails to resize the list, | ||
| 2179 | + # the argument must be released exactly once. | ||
| 2180 | + _testcapi = import_module("_testcapi") | ||
| 2181 | + | ||
| 2182 | + class Holder: | ||
| 2183 | + pass | ||
| 2184 | + | ||
| 2185 | + def list_append(l, holder): | ||
| 2186 | + # holder.item is pushed as a new reference, which | ||
| 2187 | + # CALL_LIST_APPEND steals. | ||
| 2188 | + l.append(holder.item) | ||
| 2189 | + | ||
| 2190 | + holder = Holder() | ||
| 2191 | + holder.item = item = object() | ||
| 2192 | + for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): | ||
| 2193 | + list_append([], holder) | ||
| 2194 | + self.assert_specialized(list_append, "CALL_LIST_APPEND") | ||
| 2195 | + | ||
| 2196 | + refcount = sys.getrefcount(item) | ||
| 2197 | + # An empty list has no spare capacity, so append() must resize it. | ||
| 2198 | + lst = [] | ||
| 2199 | + with self.assertRaises(MemoryError): | ||
| 2200 | + _testcapi.set_nomemory(0) | ||
| 2201 | + try: | ||
| 2202 | + list_append(lst, holder) | ||
| 2203 | + finally: | ||
| 2204 | + _testcapi.remove_mem_hooks() | ||
| 2205 | + self.assertEqual(lst, []) | ||
| 2206 | + self.assertEqual(sys.getrefcount(item), refcount) | ||
| 2207 | + | ||
| 2174 | 2208 | @cpython_only | |
| 2175 | 2209 | @requires_specialization | |
| 2176 | 2210 | def test_load_attr_module_with_getattr(self): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + Fix a double-free crash in ``list.append()`` (the specialized | ||
| 2 | + ``CALL_LIST_APPEND`` instruction) when growing the list fails with | ||
| 3 | + :exc:`MemoryError`. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5075,7 +5075,10 @@ dummy_func( | |||
| 5075 | 5075 | int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); | |
| 5076 | 5076 | UNLOCK_OBJECT(self_o); | |
| 5077 | 5077 | if (err) { | |
| 5078 | - ERROR_NO_POP(); | ||
| 5078 | + // arg is consumed even on failure: close the other inputs | ||
| 5079 | + // and pop them all, so that arg is not closed a second time. | ||
| 5080 | + DECREF_INPUTS(); | ||
| 5081 | + ERROR_IF(true); | ||
| 5079 | 5082 | } | |
| 5080 | 5083 | c = callable; | |
| 5081 | 5084 | s = self; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments