The preprocessor guard tracking in ctx_statement_block() is (and seems to have always been) subtly broken whenever tracking over an #else: the code is supposed to restore state from the current top of the stack (like and #endif just without removing it). However, it indexes the stack at [$#stack - 1]. In Perl, $# does not give you the length of an array, it gives you the highest valid index. Therefore, the correct index should just be [$#stack].
The preprocessor guard tracking also gets confused when ctx_statement_block() was called on a line that is already inside a preprocessor guard, and steps out of it within the same statement. This happens commonly with constructs like this: #if CONFIG_XXX for (a = first_a(); !a_finished(); a = next_a()) { #else for (b = first_b(); !b_finished(); b = next_b()) { #endif ... loop body ... The best course of action in this case is to not try to restore any previous state (which we don't have) at all, so we should just keep our current state if $#stack is already 0. Signed-off-by: Julius Werner <jwer...@chromium.org> --- scripts/checkpatch.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index df8b23dc1eb0af..ffccbd2033e579 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1572,9 +1572,9 @@ sub ctx_statement_block { # Handle nested #if/#else. if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { push(@stack, [ $type, $level ]); - } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { - ($type, $level) = @{$stack[$#stack - 1]}; - } elsif ($remainder =~ /^#\s*endif\b/) { + } elsif ($remainder =~ /^#\s*(?:else|elif)\b/ && $#stack > 0) { + ($type, $level) = @{$stack[$#stack]}; + } elsif ($remainder =~ /^#\s*endif\b/ && $#stack > 0) { ($type, $level) = @{pop(@stack)}; } -- 2.29.2