LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File apparmor-parser-line-numbers of Package apparmor-parser (Project home:zhy20120210:failed_1)

From: Jeff Mahoney <jeffm@suse.com>
Subject: apparmor-parser: Provide meaningful line numbers in error reports
References: bnc#520013

 The apparmor profile parser operates in a two-pass sweep. The first pass
 preprocesses the profile, handling includes and the like. The second pass
 is actually parsed.

 The problem is that the resultant preprocessed profile bears little
 resemblance to the original. Errors like "syntax error at line 213" on
 a 14 line profile serve only to confuse the user.

 This patch adds cpp-style #line directives the the preprocessed output,
 delimiting where files have been included. The result is that not only
 is the original profile's line numbers reported correctly, but included
 files are handled as well.

---
 parser_include.c |   26 ++++++++++++++++----------
 parser_lex.l     |   37 +++++++++++++++++++++++++++++++++++--
 parser_yacc.y    |   21 +++++++++++++++++++--
 3 files changed, 70 insertions(+), 14 deletions(-)

--- a/parser_include.c
+++ b/parser_include.c
@@ -84,6 +84,8 @@ static char *basedir;
 static char *default_basedir = "/etc/apparmor.d";
 static char *old_basedir = "/etc/subdomain.d";
 
+extern char *current_filename;
+
 /* start parsing.  */
 int do_include_preprocessing(char *profilename)
 {
@@ -101,12 +103,13 @@ int do_include_preprocessing(char *profi
 		profile = stdin;
 	}
 
+	current_filename = strdup(profilename ? profilename : "stdin");
+
 	/* Change to the base dir */
 	chdir(basedir);
 
 	if (preprocess_only) {
-		retval = preprocess(profile, profilename ? profilename : "stdin",
-				    stdout, 0);
+		retval = preprocess(profile, current_filename, stdout, 0);
 		goto out;
 	}
 
@@ -116,8 +119,7 @@ int do_include_preprocessing(char *profi
 		exit(10);
 	}
 
-	retval = preprocess(profile, profilename ? profilename : "stdin",
-			    tmp, 0);
+	retval = preprocess(profile, current_filename, tmp, 0);
 
 	rewind(tmp);
 
@@ -128,6 +130,11 @@ out:
 	if (profilename)
 		fclose(profile);
 
+	if (current_filename) {
+		free(current_filename);
+		current_filename = NULL;
+	}
+
 	return retval;
 }
 
@@ -429,6 +436,8 @@ static int process_include(char *inc, ch
 					err = preprocess(newf, inc + 1, out, nest + 1);
 					if (err)
 						retval = err;
+					fprintf(out, "\n#line %u \"%s\"\n",
+						line, name);
 					fclose(newf);
 				} else {
 					retval = errno;
@@ -455,18 +464,14 @@ static int preprocess(FILE * f, char *na
 	char *inc = NULL;
 	char *cwd;
 
+	fprintf(out, "\n#line 1 \"%s\"\n", name);
+
 	if (nest > MAX_NEST_LEVEL) {
 		PERROR(_("Error: Exceeded %d levels of includes.  Not processing %s include.\n"),
 		       MAX_NEST_LEVEL, name);
 		return 1;
 	}
 
-	if (nest == 0) {
-		fprintf(out, "\n#source %s\n", name);
-	} else {
-		fprintf(out, "\n#included %s\n", name);
-	}
-
 	while ((c = fgetc(f)) != EOF) {
 		int err = getincludestr(&inc, c, f, line, name, out);
 		if (err)
@@ -476,6 +481,7 @@ static int preprocess(FILE * f, char *na
 			err = process_include(inc, name, line, out, nest);
 			if (err)
 				retval = err;
+			fprintf(out, "\n#line %u \"%s\"\n", line, name);
 			chdir(cwd);
 			free(cwd);
 			free(inc);
--- a/parser_lex.l
+++ b/parser_lex.l
@@ -42,6 +42,7 @@
 #define NPDEBUG(fmt, args...)	/* Do nothing */
 
 int current_lineno = 1;
+char *current_filename = NULL;
 
 %}
 
@@ -81,12 +82,16 @@ ADD_ASSIGN	\+=
 ARROW		->
 LT_EQUAL	<=
 
+COMMENT_START	#[a-z]*
+
 %x SUB_NAME
 %x SUB_NAME2
 %x NETWORK_MODE
 %x FLAGS_MODE
 %x ASSIGN_MODE
 %x RLIMIT_MODE
+%x FILE_POS_MODE
+%x COMMENT_MODE
 
 %%
 
@@ -237,10 +242,38 @@ LT_EQUAL	<=
 			}
 }
 
-#.*\n			{ /* Comment - ignore */
+
+<FILE_POS_MODE>{
+	{WS}+		{ }
+	{NUMBER}	{
+			yylval = (YYSTYPE) strdup(yytext);
+			return TOK_VALUE;
+			}
+	{QUOTED_ID}	{
+			yylval = (YYSTYPE) processquoted(yytext, yyleng);
+			return TOK_ID;
+			}
+
+	\r?\n		{
+			BEGIN(INITIAL);
+			}
+}
+
+<COMMENT_MODE>{
+	.*\n		{
+			BEGIN(INITIAL);
 			current_lineno++;
-			PDEBUG("Line no++: %d\n", current_lineno);
 			}
+}
+
+{COMMENT_START}		{
+			if (!strcmp(yytext, "#line")) {
+				BEGIN(FILE_POS_MODE);
+				return TOK_FILE_POS;
+			}
+			BEGIN(COMMENT_MODE);
+			}
+
 
 {END_OF_RULE}		{ return TOK_END_OF_RULE; }
 
--- a/parser_yacc.y
+++ b/parser_yacc.y
@@ -58,8 +58,8 @@
 static struct flagval force_complain_flags = {0, 1, 0};
 
 /* from lex_config, for nice error messages */
-/* extern char *current_file; */
 extern int current_lineno;
+extern char *current_filename;
 
 struct value_list {
 	char *value;
@@ -139,6 +139,9 @@ struct codomain *do_local_profile(struct
 %token TOK_FLAG_SEP
 %token TOK_FLAG_ID
 
+%token TOK_FILE_POS
+%token TOK_COMMENT
+
 %union {
 	char *id;
 	char *flag_id;
@@ -208,6 +211,8 @@ opt_profile_flag: { /* nothing */ $$ = 0
 	| TOK_PROFILE { $$ = 1; }
 	| hat_start { $$ = 2; }
 
+profile: file_position
+
 profile:	opt_profile_flag TOK_ID flags TOK_OPEN rules TOK_CLOSE
 	{
 		struct codomain *cod = $5;
@@ -263,6 +268,7 @@ profile:	opt_profile_flag TOK_COLON TOK_
 preamble: { /* nothing */ }
 	| preamble alias { /* nothing */ };
 	| preamble varassign { /* nothing */ };
+	| preamble file_position { };
 
 alias: TOK_ALIAS TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
 	{
@@ -712,6 +718,8 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID T
 		$$ = $1;
 	};
 
+rules: rules file_position
+
 
 cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
 	{
@@ -1059,6 +1067,15 @@ caps: TOK_ID
 		$$ = CAP_TO_MASK(cap);
 	};
 
+file_position: TOK_FILE_POS TOK_VALUE TOK_ID
+	{
+		if (current_filename)
+			free(current_filename);
+		current_filename = $3;
+		current_lineno = atoi($2);
+		free($2);
+	};
+
 %%
 #define MAXBUFSIZE 4096
 
@@ -1073,7 +1090,7 @@ void yyerror(char *msg, ...)
 
 	if (profilename) {
 		PERROR(_("AppArmor parser error in %s at line %d: %s\n"),
-		       profilename, current_lineno, buf);
+		       current_filename, current_lineno, buf);
 	} else {
 		PERROR(_("AppArmor parser error, line %d: %s\n"),
 		       current_lineno, buf);