Skip to content

Commit 1a318a0

Browse files
Avoid expensive list/tuple multiplication operations (#2228)
1 parent ae9b753 commit 1a318a0

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ Release date: TBA
189189

190190
Closes pylint-dev/pylint#8749
191191

192+
* Avoid expensive list/tuple multiplication operations that would result in ``MemoryError``.
193+
194+
Closes pylint-dev/pylint#8748
195+
192196

193197
What's New in astroid 2.15.5?
194198
=============================

astroid/protocols.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,19 @@ def const_infer_binary_op(
163163
def _multiply_seq_by_int(
164164
self: _TupleListNodeT,
165165
opnode: nodes.AugAssign | nodes.BinOp,
166-
other: nodes.Const,
166+
value: int,
167167
context: InferenceContext,
168168
) -> _TupleListNodeT:
169169
node = self.__class__(parent=opnode)
170+
if value > 1e8:
171+
node.elts = [util.Uninferable]
172+
return node
170173
filtered_elts = (
171174
helpers.safe_infer(elt, context) or util.Uninferable
172175
for elt in self.elts
173176
if not isinstance(elt, util.UninferableBase)
174177
)
175-
node.elts = list(filtered_elts) * other.value
178+
node.elts = list(filtered_elts) * value
176179
return node
177180

178181

@@ -221,14 +224,17 @@ def tl_infer_binary_op(
221224
if not isinstance(other.value, int):
222225
yield not_implemented
223226
return
224-
yield _multiply_seq_by_int(self, opnode, other, context)
227+
yield _multiply_seq_by_int(self, opnode, other.value, context)
225228
elif isinstance(other, bases.Instance) and operator == "*":
226229
# Verify if the instance supports __index__.
227230
as_index = helpers.class_instance_as_index(other)
228231
if not as_index:
229232
yield util.Uninferable
233+
elif not isinstance(as_index.value, int): # pragma: no cover
234+
# already checked by class_instance_as_index() but faster than casting
235+
raise AssertionError("Please open a bug report.")
230236
else:
231-
yield _multiply_seq_by_int(self, opnode, as_index, context)
237+
yield _multiply_seq_by_int(self, opnode, as_index.value, context)
232238
else:
233239
yield not_implemented
234240

tests/test_protocols.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ def test_uninferable_exponents() -> None:
279279
parsed = extract_node("None ** 2")
280280
assert parsed.inferred() == [Uninferable]
281281

282+
@staticmethod
283+
def test_uninferable_list_multiplication() -> None:
284+
"""Attempting to calculate the result is prohibitively expensive."""
285+
parsed = extract_node("[0] * 123456789")
286+
element = parsed.inferred()[0].elts[0]
287+
assert element.value is Uninferable
288+
282289

283290
def test_named_expr_inference() -> None:
284291
code = """

0 commit comments

Comments
 (0)