summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorNir Soffer <nirsof@gmail.com>2017-07-08 18:51:21 (GMT)
committerBerker Peksag <berker.peksag@gmail.com>2017-07-08 18:51:21 (GMT)
commit04f77d4677e7508b6ec8de9d0331fdabbcd11d30 (patch)
treea221699df6ca87da7301f344ed97ce7bfc83e837 /Lib
parent03e0df66b8ce0a8d980eb2092b7c6464d26db14e (diff)
downloadcpython-04f77d4677e7508b6ec8de9d0331fdabbcd11d30.zip
cpython-04f77d4677e7508b6ec8de9d0331fdabbcd11d30.tar.gz
cpython-04f77d4677e7508b6ec8de9d0331fdabbcd11d30.tar.bz2
[3.6] bpo-29854: Fix segfault in call_readline() (GH-728)
If history-length is set in .inputrc, and the history file is double the history size (or more), history_get(N) returns NULL, and python segfaults. Fix that by checking for NULL return value. It seems that the root cause is incorrect handling of bigger history in readline, but Python should not segfault even if readline returns unexpected value. This issue affects only GNU readline. When using libedit emulation system history size option does not work.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_readline.py50
1 files changed, 47 insertions, 3 deletions
diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py
index 06a9149..9c979652 100644
--- a/Lib/test/test_readline.py
+++ b/Lib/test/test_readline.py
@@ -9,7 +9,7 @@ import subprocess
import sys
import tempfile
import unittest
-from test.support import import_module, unlink, TESTFN
+from test.support import import_module, unlink, temp_dir, TESTFN
from test.support.script_helper import assert_python_ok
# Skip tests if there is no readline module
@@ -210,13 +210,57 @@ print("history", ascii(readline.get_history_item(1)))
self.assertIn(b"result " + expected + b"\r\n", output)
self.assertIn(b"history " + expected + b"\r\n", output)
+ # We have 2 reasons to skip this test:
+ # - readline: history size was added in 6.0
+ # See https://cnswww.cns.cwru.edu/php/chet/readline/CHANGES
+ # - editline: history size is broken on OS X 10.11.6.
+ # Newer versions were not tested yet.
+ @unittest.skipIf(readline._READLINE_VERSION < 0x600,
+ "this readline version does not support history-size")
+ @unittest.skipIf(is_editline,
+ "editline history size configuration is broken")
+ def test_history_size(self):
+ history_size = 10
+ with temp_dir() as test_dir:
+ inputrc = os.path.join(test_dir, "inputrc")
+ with open(inputrc, "wb") as f:
+ f.write(b"set history-size %d\n" % history_size)
+
+ history_file = os.path.join(test_dir, "history")
+ with open(history_file, "wb") as f:
+ # history_size * 2 items crashes readline
+ data = b"".join(b"item %d\n" % i
+ for i in range(history_size * 2))
+ f.write(data)
+
+ script = """
+import os
+import readline
+
+history_file = os.environ["HISTORY_FILE"]
+readline.read_history_file(history_file)
+input()
+readline.write_history_file(history_file)
+"""
+
+ env = dict(os.environ)
+ env["INPUTRC"] = inputrc
+ env["HISTORY_FILE"] = history_file
+
+ run_pty(script, input=b"last input\r", env=env)
+
+ with open(history_file, "rb") as f:
+ lines = f.readlines()
+ self.assertEqual(len(lines), history_size)
+ self.assertEqual(lines[-1].strip(), b"last input")
+
-def run_pty(script, input=b"dummy input\r"):
+def run_pty(script, input=b"dummy input\r", env=None):
pty = import_module('pty')
output = bytearray()
[master, slave] = pty.openpty()
args = (sys.executable, '-c', script)
- proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave)
+ proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave, env=env)
os.close(slave)
with ExitStack() as cleanup:
cleanup.enter_context(proc)