kconfig: preserve the final answer when input has no newline
PATCH v2 1/1 kconfig: preserve the final answer when input has no newline
conf_string() unconditionally removes the last character returned by fgets(), assuming that it is a newline. When redirected input ends without a newline, the last character is part of the answer instead. For example, feeding 42 to an integer prompt stores 4, and feeding 0xff to a hexadecimal prompt stores 0xf. Both commands succeed despite silently changing the supplied value.
Strip the newline with strcspn() so that a complete answer at EOF is preserved. Keep the existing handling of newline-terminated and empty answers unchanged.
Add regression tests for string, int and hex answers, with and without a final newline, in oldaskconfig and oldconfig.
---
Changes in v2, addressing Julian Braha's review:
- Add an in-tree regression test under scripts/kconfig/tests for string, int and hex answers, with and without a final newline, in oldconfig and oldaskconfig. The shared test harness is unchanged.
- Submit this fix independently of the checkkconfigsymbols.py change.
- Refresh Cc from scripts/get_maintainer.pl, including the LLVM contacts.
v1: https://lore.kernel.org/all/[email protected]/
An AI coding assistant found the issue, prepared the fix and changelog, and ran the original verification. The assistant also prepared the new regression test and this v2 revision.
Validation:
- Built original and fixed conf with Clang on macOS and GCC in an x86_64 Linux container, using -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror.
- On both platforms, the original conf fails all six unterminated-input cases and passes all six newline-terminated controls.
- The fixed conf passes the complete 33-test Kconfig suite on both platforms, including all 12 new cases.
- This tests the host configuration tool; a complete kernel was not built.
scripts/kconfig/conf.c | 2 +- .../kconfig/tests/conf_no_newline/__init__.py | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 scripts/kconfig/tests/conf_no_newline/__init__.py
scripts/kconfig/conf.c +1 -1
@@ -343,7 +343,7 @@ static int conf_string(struct menu *menu) }/* fall through */ default : - line[strlen (line)-1 ] =0 ; + line[strcspn (line,"\n" )] =0 ; def = line; }if (def &&sym_set_string_value (sym, def))
scripts/kconfig/tests/conf_no_newline/__init__.py new file +32 -0
@@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Preserve complete string, int and hex answers at end of input. +""" + +import subprocess + +import pytest + +from conftest import CONF_PATH + + [email protected]('mode', ['--oldaskconfig', '--oldconfig']) [email protected]('newline', ['', '\n'], ids=['eof', 'newline']) [email protected]('symbol_type, value, expected', [ + ('string', 'abcdef', '"abcdef"'), + ('int', '42', '42'), + ('hex', '0xff', '0xff'), +]) +def test(mode, newline, symbol_type, value, expected, tmp_path, monkeypatch): + (tmp_path / 'Kconfig').write_text( + 'config TEST\n\t{} "Test value"\n'.format(symbol_type)) + monkeypatch.setenv('srctree', str(tmp_path)) + monkeypatch.setenv('KCONFIG_DEFCONFIG_LIST', '') + + result = subprocess.run([CONF_PATH, mode, 'Kconfig'], + input=value + newline, text=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + cwd=tmp_path, timeout=10) + + assert result.returncode == 0, result.stderr + assert 'CONFIG_TEST={}\n'.format(expected) in (tmp_path / '.config').read_text()
base-commit: 4d7d9486c04d917265f64c55bd23b2cc4fe7749c
Signature · 1 line
2.50.1 (Apple Git-155)
Julian Braha
reviewerHi Erkan,
Quoted 76 lines · Erkan Erdem
conf_string()unconditionally removes the last character returned byfgets(), assuming that it is a newline. When redirected input ends without a newline, the last character is part of the answer instead. For example, feeding 42 to an integer prompt stores 4, and feeding0xffto a hexadecimal prompt stores0xf. Both commands succeed despite silently changing the supplied value.Strip the newline with
strcspn()so that a complete answer at EOF is preserved. Keep the existing handling of newline-terminated and empty answers unchanged.Add regression tests for string, int and hex answers, with and without a final newline, in oldaskconfig and oldconfig.
---
Changes in v2, addressing Julian Braha's review:
- Add an in-tree regression test underscripts/kconfig/testsfor string, int and hex answers, with and without a final newline, in oldconfig and oldaskconfig. The shared test harness is unchanged.
- Submit this fix independently of thecheckkconfigsymbols.pychange.
- Refresh Cc fromscripts/get_maintainer.pl, including the LLVM contacts.v1: https://lore.kernel.org/all/[email protected]/
An AI coding assistant found the issue, prepared the fix and changelog, and ran the original verification. The assistant also prepared the new regression test and this v2 revision.
Validation:
- Built original and fixed conf with Clang on macOS and GCC in anx86_64Linux container, using -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror.
- On both platforms, the original conf fails all six unterminated-input cases and passes all six newline-terminated controls.
- The fixed conf passes the complete 33-testKconfigsuite on both platforms, including all 12 new cases.
- This tests the host configuration tool; a complete kernel was not built.scripts/kconfig/conf.c | 2 +- .../kconfig/tests/conf_no_newline/__init__.py | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 scripts/kconfig/tests/conf_no_newline/__init__.pyscripts/kconfig/conf.c +1
-1@@ -343,7 +343,7 @@ static int conf_string(struct menu *menu) }/* fall through */ default : - line[strlen (line)-1 ] =0 ; + line[strcspn (line,"\n" )] =0 ; def = line; }if (def &&sym_set_string_value (sym, def))scripts/kconfig/tests/conf_no_newline/__init__.py new file +10
-0@@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +""" +Preserve complete string, int and hex answers at end of input. +""" + +import subprocess + +import pytest + +from conftest import CONF_PATH
scripts/kconfig/tests/conf_no_newline/__init__.py line 20
Quoted 10 lines
scripts/kconfig/tests/conf_no_newline/__init__.py new file +10
-0+ + [email protected]('mode', ['--oldaskconfig', '--oldconfig']) [email protected]('newline', ['', '\n'], ids=['eof', 'newline']) [email protected]('symbol_type, value, expected', [ + ('string', 'abcdef', '"abcdef"'), + ('int', '42', '42'), + ('hex', '0xff', '0xff'), +]) +def test(mode, newline, symbol_type, value, expected, tmp_path, monkeypatch):
Please follow the style of the existing Kconfig tests.
For example, the function signature should look like 'def test(conf):'
scripts/kconfig/tests/conf_no_newline/__init__.py line 22
Quoted 2 lines
scripts/kconfig/tests/conf_no_newline/__init__.py new file +2
-0+ (tmp_path / 'Kconfig').write_text( + 'config TEST\n\t{} "Test value"\n'.format(symbol_type))
And you should keep a minimal Kconfig file in the directory, instead of having the test create a temporary file each time it runs.
Quoted 11 lines
scripts/kconfig/tests/conf_no_newline/__init__.py new file +10
-0+ monkeypatch.setenv('srctree', str(tmp_path)) + monkeypatch.setenv('KCONFIG_DEFCONFIG_LIST', '') + + result = subprocess.run([CONF_PATH, mode, 'Kconfig'], + input=value + newline, text=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + cwd=tmp_path, timeout=10) + + assert result.returncode == 0, result.stderr + assert 'CONFIG_TEST={}\n'.format(expected) in (tmp_path / '.config').read_text()
Quoted 1 line
base-commit:
4d7d9486c04d917265f64c55bd23b2cc4fe7749c
- Julian Braha