[PATCH] parse: warn on trailing whitespace after line continuation backslash
Jaipaul Cheernam <[email protected]>
| Newsgroups | org.openembedded.lists.bitbake-devel |
|---|---|
| Message-ID | <[email protected]> |
rstrip() is called before checking for backslash, so trailing spaces or
tabs after "\" go unnoticed. For example:
file://foo.patch \<TAB>
file://bar.patch \
The first line has a trailing tab after the backslash that is invisible
but ends up in patch context, causing patches to fail to apply on trees
where it was cleaned up.
Emit a warning when this is detected so developers can fix it early.
Tested with bitbake-selftest:
$ python3 -m unittest lib.bb.tests.parse.ParseTest.test_parse_trailing_whitespace_continuation -v
$ python3 -m unittest lib.bb.tests.parse.ParseTest.test_parse_clean_continuation_no_warning -v
2 tests OK
Signed-off-by: Jaipaul Cheernam <[email protected]>
---
Problem:
Ran into this while submitting libssh2 CVE patches to both master and
wrynose. The libssh2_1.11.1.bb on master has a stray tab after the
backslash on the CVE-2025-15661-3.patch line. Patches adding new file://
lines below it applied fine on master but git-am refused them on wrynose
because that branch doesn't have the trailing tab — context mismatch.
Other recipes in oe-core with the same issue:
autoconf_2.73.bb:2
perl_5.44.0.bb:313,314
mc_4.8.33.bb:50,51
libxml-sax-perl_1.02.bb:4
A separate series will follow to fix the trailing whitespace in the
affected recipes.
lib/bb/parse/parse_py/BBHandler.py | 6 +++++-
lib/bb/parse/parse_py/ConfHandler.py | 10 ++++++++--
lib/bb/tests/parse.py | 19 +++++++++++++++++++
3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/lib/bb/parse/parse_py/BBHandler.py b/lib/bb/parse/parse_py/BBHandler.py
index 008fec230..710ea04d4 100644
--- a/lib/bb/parse/parse_py/BBHandler.py
+++ b/lib/bb/parse/parse_py/BBHandler.py
@@ -104,7 +104,11 @@ def get_statements(filename, absolute_filename, base_name):
lineno = lineno + 1
s = f.readline()
if not s: break
- s = s.rstrip()
+ # Warn if trailing whitespace exists after a continuation backslash
+ raw = s.rstrip('\n').rstrip('\r')
+ s = raw.rstrip()
+ if s and s[-1] == '\\' and raw != s:
+ bb.warn("Trailing whitespace after line continuation backslash in %s, line %s" % (filename, lineno))
feeder(lineno, s, filename, base_name, statements)
if __inpython__:
diff --git a/lib/bb/parse/parse_py/ConfHandler.py b/lib/bb/parse/parse_py/ConfHandler.py
index 9ddbae123..07b0c371f 100644
--- a/lib/bb/parse/parse_py/ConfHandler.py
+++ b/lib/bb/parse/parse_py/ConfHandler.py
@@ -134,12 +134,18 @@ def handle(fn, data, include, baseconfig=False):
# skip empty lines
if not w:
continue
- s = s.rstrip()
+ raw = s.rstrip('\n').rstrip('\r')
+ s = raw.rstrip()
+ if s and s[-1] == '\\' and raw != s:
+ bb.warn("Trailing whitespace after line continuation backslash in %s, line %s" % (fn, lineno))
while s[-1] == '\\':
line = f.readline()
origline += line
- s2 = line.rstrip()
+ raw2 = line.rstrip('\n').rstrip('\r')
+ s2 = raw2.rstrip()
lineno = lineno + 1
+ if s2 and s2[-1] == '\\' and raw2 != s2:
+ bb.warn("Trailing whitespace after line continuation backslash in %s, line %s" % (fn, lineno))
if (not s2 or s2 and s2[0] != "#") and s[0] == "#" :
bb.fatal("There is a confusing multiline, partially commented expression starting on line %s of file %s:\n%s\nPlease clarify whether this is all a comment or should be parsed." % (origlineno, fn, origline))
diff --git a/lib/bb/tests/parse.py b/lib/bb/tests/parse.py
index 6ac2137e0..b01932350 100644
--- a/lib/bb/tests/parse.py
+++ b/lib/bb/tests/parse.py
@@ -638,3 +638,22 @@ EXTRA_OECONF:append = " foobar"
output = run_bitbake(["bitbake", "-e", "recipe-file1"], builddir, extraenv).splitlines()
self.assertIn('BBCLASS_FILE="recipe-file.inc"', output)
self.assertIn(f'BBCLASS_RECIPE_FILE="recipe-file1.bb"', output)
+
+ trailing_whitespace_continuation = "A = \"1 \\\t \n2\"\n"
+
+ def test_parse_trailing_whitespace_continuation(self):
+ """Test that trailing whitespace after backslash continuation emits a warning"""
+ with self.parsehelper(self.trailing_whitespace_continuation) as f:
+ with self.assertLogs('BitBake', level='WARNING') as cm:
+ d = bb.parse.handle(f.name, self.d)['']
+ self.assertTrue(any("Trailing whitespace after line continuation backslash" in msg for msg in cm.output))
+ # Verify it still parses correctly despite the warning
+ self.assertEqual(d.getVar("A"), "1 2")
+
+ clean_continuation = "A = \"1 \\\n2\"\n"
+
+ def test_parse_clean_continuation_no_warning(self):
+ """Test that clean backslash continuation does not warn"""
+ with self.parsehelper(self.clean_continuation) as f:
+ d = bb.parse.handle(f.name, self.d)['']
+ self.assertEqual(d.getVar("A"), "1 2")