chainlint.sed: don't mistake `<< word` in string as here-doc operator

Tighten here-doc recognition to prevent it from being fooled by text which looks like a here-doc operator but happens merely to be the content of a string, such as this real-world case from t7201: echo "<<<<<<< ours" && echo ourside && echo "=======" && echo theirside && echo ">>>>>>> theirs" This problem went unnoticed because chainlint.sed is not a real parser, but rather applies heuristics to pretend to understand shell code. In this case, it saw what it thought was a here-doc operator (`<< ours`), and fell off the end of the test looking for the closing tag "ours" which it never found, thus swallowed the remainder of the test without checking it for &&-chain breakage. Signed-off-by: Eric Sunshine <sunshine@sunshineco.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Eric Sunshine committed Dec 13, 2021 at 01:30 UTC 22597af97d67660fb3f0dba538a1f02b1ba94243
3 files changed +36 -2
t/chainlint.sed
+6 -2
@@ -89,6 +89,7 @@
89 # here-doc -- swallow it to avoid false hits within its body (but keep the
90 # command to which it was attached)
91 /<<-*[ ]*[\\'"]*[A-Za-z0-9_]/ {
92 + /"[^"]*<<[^"]*"/bnotdoc
93 s/^\(.*\)<<-*[ ]*[\\'"]*\([A-Za-z0-9_][A-Za-z0-9_]*\)['"]*/<\2>\1<</
94 s/[ ]*<<//
95 :hered
@@ -100,6 +101,7 @@
101 s/^<[^>]*>//
102 s/\n.*$//
103 }
104 +:notdoc
105
106 # one-liner "(...) &&"
107 /^[ ]*!*[ ]*(..*)[ ]*&&[ ]*$/boneline
@@ -151,8 +153,10 @@ s/.*\n//
153 /"[^'"]*'[^'"]*"/!bsqstr
154 }
155 :folded
154 -# here-doc -- swallow it
155 -/<<-*[ ]*[\\'"]*[A-Za-z0-9_]/bheredoc
156 +# here-doc -- swallow it (but not "<<" in a string)
157 +/<<-*[ ]*[\\'"]*[A-Za-z0-9_]/{
158 + /"[^"]*<<[^"]*"/!bheredoc
159 +}
160 # comment or empty line -- discard since final non-comment, non-empty line
161 # before closing ")", "done", "elsif", "else", or "fi" will need to be
162 # re-visited to drop "suspect" marking since final line of those constructs
t/chainlint/not-heredoc.expect new
+14
@@ -0,0 +1,14 @@
1 +echo "<<<<<<< ours" &&
2 +echo ourside &&
3 +echo "=======" &&
4 +echo theirside &&
5 +echo ">>>>>>> theirs" &&
6 +
7 +(
8 + echo "<<<<<<< ours" &&
9 + echo ourside &&
10 + echo "=======" &&
11 + echo theirside &&
12 + echo ">>>>>>> theirs" ?!AMP?!
13 + poodle
14 +) >merged
t/chainlint/not-heredoc.test new
+16
@@ -0,0 +1,16 @@
1 +# LINT: "<< ours" inside string is not here-doc
2 +echo "<<<<<<< ours" &&
3 +echo ourside &&
4 +echo "=======" &&
5 +echo theirside &&
6 +echo ">>>>>>> theirs" &&
7 +
8 +(
9 +# LINT: "<< ours" inside string is not here-doc
10 + echo "<<<<<<< ours" &&
11 + echo ourside &&
12 + echo "=======" &&
13 + echo theirside &&
14 + echo ">>>>>>> theirs"
15 + poodle
16 +) >merged