Module Name:    src
Committed By:   rillig
Date:           Sat Jun 10 17:35:41 UTC 2023

Modified Files:
        src/tests/usr.bin/indent: opt_cli.c psym_else.c t_errors.sh
        src/usr.bin/indent: parse.c

Log Message:
indent: fix stack overflow, add more tests

For several parser symbols, 2 symbols are pushed in a row, which led to
an out-of-bounds write.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/tests/usr.bin/indent/opt_cli.c
cvs rdiff -u -r1.4 -r1.5 src/tests/usr.bin/indent/psym_else.c
cvs rdiff -u -r1.34 -r1.35 src/tests/usr.bin/indent/t_errors.sh
cvs rdiff -u -r1.71 -r1.72 src/usr.bin/indent/parse.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/usr.bin/indent/opt_cli.c
diff -u src/tests/usr.bin/indent/opt_cli.c:1.6 src/tests/usr.bin/indent/opt_cli.c:1.7
--- src/tests/usr.bin/indent/opt_cli.c:1.6	Tue Jun  6 04:37:27 2023
+++ src/tests/usr.bin/indent/opt_cli.c	Sat Jun 10 17:35:41 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: opt_cli.c,v 1.6 2023/06/06 04:37:27 rillig Exp $ */
+/* $NetBSD: opt_cli.c,v 1.7 2023/06/10 17:35:41 rillig Exp $ */
 
 /*
  * Tests for the option '-cli' ("case label indentation"), which sets the
@@ -97,3 +97,54 @@ classify(int n)
 	}
 }
 //indent end
+
+
+/*
+ * Test the combination of left-aligned braces and a deep case indentation.
+ *
+ * When the 'case' labels are that deeply indented, the distance between the
+ * braces and the 'case' is between 1 and 2 indentation levels.
+ */
+//indent input
+{
+switch (expr)
+{
+case 1:
+}
+}
+//indent end
+
+//indent run -br -cli3.25
+{
+	switch (expr) {
+				  case 1:
+	}
+}
+//indent end
+
+//indent run -bl -cli3.25
+{
+	switch (expr)
+			{
+				  case 1:
+			}
+}
+//indent end
+
+//indent run -bl -cli2.75
+{
+	switch (expr)
+		{
+			      case 1:
+		}
+}
+//indent end
+
+//indent run -bl -cli1.25
+{
+	switch (expr)
+	{
+		  case 1:
+	}
+}
+//indent end

Index: src/tests/usr.bin/indent/psym_else.c
diff -u src/tests/usr.bin/indent/psym_else.c:1.4 src/tests/usr.bin/indent/psym_else.c:1.5
--- src/tests/usr.bin/indent/psym_else.c:1.4	Sun Apr 24 10:36:37 2022
+++ src/tests/usr.bin/indent/psym_else.c	Sat Jun 10 17:35:41 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: psym_else.c,v 1.4 2022/04/24 10:36:37 rillig Exp $ */
+/* $NetBSD: psym_else.c,v 1.5 2023/06/10 17:35:41 rillig Exp $ */
 
 /*
  * Tests for the parser symbol psym_else, which represents the keyword 'else'
@@ -71,3 +71,18 @@ function(void)
 		(var = 3);
 }
 //indent end
+
+
+//indent input
+{
+	else
+}
+//indent end
+
+//indent run
+error: Standard Input:2: Unmatched 'else'
+{
+	else
+}
+exit 1
+//indent end

Index: src/tests/usr.bin/indent/t_errors.sh
diff -u src/tests/usr.bin/indent/t_errors.sh:1.34 src/tests/usr.bin/indent/t_errors.sh:1.35
--- src/tests/usr.bin/indent/t_errors.sh:1.34	Fri Jun  9 11:22:31 2023
+++ src/tests/usr.bin/indent/t_errors.sh	Sat Jun 10 17:35:41 2023
@@ -1,5 +1,5 @@
 #! /bin/sh
-# $NetBSD: t_errors.sh,v 1.34 2023/06/09 11:22:31 rillig Exp $
+# $NetBSD: t_errors.sh,v 1.35 2023/06/10 17:35:41 rillig Exp $
 #
 # Copyright (c) 2021 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -485,6 +485,32 @@ EOF
 	    "$indent" -l34 code.c -st
 }
 
+atf_test_case 'stack_overflow'
+stack_overflow_body()
+{
+	cat <<-EOF > code.c
+		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
+		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
+		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{
+	EOF
+
+	atf_check \
+	    -s 'exit:1' \
+	    -e 'inline:error: code.c:3: Stuff missing from end of file\n' \
+	    "$indent" code.c
+
+	cat <<-EOF > code.c
+		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
+		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{ {{{{{{{{{{
+		{{{{{{{{{{ {{{{{{{{{{ {{{{{{{ {
+	EOF
+
+	atf_check \
+	    -s 'exit:1' \
+	    -e 'inline:indent: Parser stack overflow\n' \
+	    "$indent" code.c
+}
+
 
 atf_init_test_cases()
 {
@@ -524,4 +550,5 @@ atf_init_test_cases()
 	atf_add_test_case 'gcc_statement_expression'
 	atf_add_test_case 'crash_comment_after_controlling_expression'
 	atf_add_test_case 'comment_fits_in_one_line'
+	atf_add_test_case 'stack_overflow'
 }

Index: src/usr.bin/indent/parse.c
diff -u src/usr.bin/indent/parse.c:1.71 src/usr.bin/indent/parse.c:1.72
--- src/usr.bin/indent/parse.c:1.71	Sat Jun 10 16:43:56 2023
+++ src/usr.bin/indent/parse.c	Sat Jun 10 17:35:40 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: parse.c,v 1.71 2023/06/10 16:43:56 rillig Exp $	*/
+/*	$NetBSD: parse.c,v 1.72 2023/06/10 17:35:40 rillig Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-4-Clause
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: parse.c,v 1.71 2023/06/10 16:43:56 rillig Exp $");
+__RCSID("$NetBSD: parse.c,v 1.72 2023/06/10 17:35:40 rillig Exp $");
 
 #include <err.h>
 
@@ -101,17 +101,13 @@ decl_level(void)
 }
 
 static void
-ps_push(parser_symbol psym)
-{
-	ps.psyms.sym[++ps.psyms.top] = psym;
-	ps.psyms.ind_level[ps.psyms.top] = ps.ind_level;
-}
-
-static void
-ps_push_follow(parser_symbol psym)
+ps_push(parser_symbol psym, bool follow)
 {
+	if (ps.psyms.top + 1 >= STACKSIZE)
+		errx(1, "Parser stack overflow");
 	ps.psyms.sym[++ps.psyms.top] = psym;
-	ps.psyms.ind_level[ps.psyms.top] = ps.ind_level_follow;
+	ps.psyms.ind_level[ps.psyms.top] =
+	    follow ? ps.ind_level_follow : ps.ind_level;
 }
 
 /*
@@ -180,8 +176,8 @@ parse(parser_symbol psym)
 				--ps.ind_level;
 		}
 
-		ps_push(psym);
-		ps_push_follow(psym_stmt);
+		ps_push(psym, false);
+		ps_push(psym_stmt, true);
 		break;
 
 	case psym_rbrace:
@@ -201,7 +197,7 @@ parse(parser_symbol psym)
 			break;	/* only put one declaration onto stack */
 
 		ps.break_after_comma = true;
-		ps_push_follow(psym_decl);
+		ps_push(psym_decl, true);
 
 		if (opt.left_justify_decl)
 			ps.ind_level_follow = ps.ind_level = decl_level();
@@ -209,7 +205,7 @@ parse(parser_symbol psym)
 
 	case psym_stmt:
 		ps.break_after_comma = false;
-		ps_push(psym_stmt);
+		ps_push(psym_stmt, false);
 		break;
 
 	case psym_if_expr:
@@ -220,7 +216,7 @@ parse(parser_symbol psym)
 	case psym_do:
 	case psym_for_exprs:
 		ps.ind_level = ps.ind_level_follow++;
-		ps_push(psym);
+		ps_push(psym, false);
 		break;
 
 	case psym_else:
@@ -234,7 +230,7 @@ parse(parser_symbol psym)
 		break;
 
 	case psym_switch_expr:
-		ps_push_follow(psym_switch_expr);
+		ps_push(psym_switch_expr, true);
 		ps.ind_level_follow += (int)opt.case_indent + 1;
 		break;
 
@@ -242,9 +238,9 @@ parse(parser_symbol psym)
 		if (psyms->sym[psyms->top] == psym_do_stmt) {
 			ps.ind_level = ps.ind_level_follow =
 			    psyms->ind_level[psyms->top];
-			ps_push(psym_while_expr);
+			ps_push(psym_while_expr, false);
 		} else {
-			ps_push_follow(psym_while_expr);
+			ps_push(psym_while_expr, true);
 			++ps.ind_level_follow;
 		}
 		break;
@@ -254,9 +250,6 @@ parse(parser_symbol psym)
 		return;
 	}
 
-	if (psyms->top >= STACKSIZE - 1)
-		errx(1, "Parser stack overflow");
-
 	debug_psyms_stack("before reduction");
 	psyms_reduce(&ps.psyms);
 	debug_psyms_stack("after reduction");

Reply via email to