https://github.com/python/cpython/commit/1a2b0fb3e5eac4e767e6bbb0b2c3cedaedafc07b
commit: 1a2b0fb3e5eac4e767e6bbb0b2c3cedaedafc07b
branch: 3.13
author: Stan Ulbrych <[email protected]>
committer: pablogsal <[email protected]>
date: 2026-02-28T13:49:37Z
summary:
[3.13] gh-144759: Fix undefined behavior from NULL pointer arithmetic in lexer
(GH-144788) (#145355)
files:
A Misc/NEWS.d/next/Core and
Builtins/2026-02-13-12-00-00.gh-issue-144759.d3qYpe.rst
M Lib/test/test_repl.py
M Parser/lexer/buffer.c
diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py
index b55a5180c67786..855dca2258d2a8 100644
--- a/Lib/test/test_repl.py
+++ b/Lib/test/test_repl.py
@@ -143,6 +143,22 @@ def test_multiline_string_parsing(self):
output = kill_python(p)
self.assertEqual(p.returncode, 0)
+ @cpython_only
+ def test_lexer_buffer_realloc_with_null_start(self):
+ # gh-144759: NULL pointer arithmetic in the lexer when start and
+ # multi_line_start are NULL (uninitialized in tok_mode_stack[0])
+ # and the lexer buffer is reallocated while parsing long input.
+ long_value = "a" * 2000
+ user_input = dedent(f"""\
+ x = f'{{{long_value!r}}}'
+ print(x)
+ """)
+ p = spawn_repl()
+ p.stdin.write(user_input)
+ output = kill_python(p)
+ self.assertEqual(p.returncode, 0)
+ self.assertIn(long_value, output)
+
def test_close_stdin(self):
user_input = dedent('''
import os
diff --git a/Misc/NEWS.d/next/Core and
Builtins/2026-02-13-12-00-00.gh-issue-144759.d3qYpe.rst b/Misc/NEWS.d/next/Core
and Builtins/2026-02-13-12-00-00.gh-issue-144759.d3qYpe.rst
new file mode 100644
index 00000000000000..46786d0672b0a8
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and
Builtins/2026-02-13-12-00-00.gh-issue-144759.d3qYpe.rst
@@ -0,0 +1,4 @@
+Fix undefined behavior in the lexer when ``start`` and ``multi_line_start``
+pointers are ``NULL`` in ``_PyLexer_remember_fstring_buffers()`` and
+``_PyLexer_restore_fstring_buffers()``. The ``NULL`` pointer arithmetic
+(``NULL - valid_pointer``) is now guarded with explicit ``NULL`` checks.
diff --git a/Parser/lexer/buffer.c b/Parser/lexer/buffer.c
index f6502bf8f7f2d1..6815e055d24c60 100644
--- a/Parser/lexer/buffer.c
+++ b/Parser/lexer/buffer.c
@@ -13,8 +13,8 @@ _PyLexer_remember_fstring_buffers(struct tok_state *tok)
for (index = tok->tok_mode_stack_index; index >= 0; --index) {
mode = &(tok->tok_mode_stack[index]);
- mode->f_string_start_offset = mode->f_string_start - tok->buf;
- mode->f_string_multi_line_start_offset =
mode->f_string_multi_line_start - tok->buf;
+ mode->f_string_start_offset = mode->f_string_start == NULL ? -1 :
mode->f_string_start - tok->buf;
+ mode->f_string_multi_line_start_offset =
mode->f_string_multi_line_start == NULL ? -1 : mode->f_string_multi_line_start
- tok->buf;
}
}
@@ -27,8 +27,8 @@ _PyLexer_restore_fstring_buffers(struct tok_state *tok)
for (index = tok->tok_mode_stack_index; index >= 0; --index) {
mode = &(tok->tok_mode_stack[index]);
- mode->f_string_start = tok->buf + mode->f_string_start_offset;
- mode->f_string_multi_line_start = tok->buf +
mode->f_string_multi_line_start_offset;
+ mode->f_string_start = mode->f_string_start_offset < 0 ? NULL :
tok->buf + mode->f_string_start_offset;
+ mode->f_string_multi_line_start =
mode->f_string_multi_line_start_offset < 0 ? NULL : tok->buf +
mode->f_string_multi_line_start_offset;
}
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]