shithub: scc

Download patch

ref: 04f9a41d5d31d47cbdadc71b4637f19e880f94e2
parent: 4428ef865b3be5188fdf0c986ef5a0e114230484
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Jan 30 10:52:29 EST 2017

[cc1] Use LOC variables for input

It is a bad idea to use the values stored directly in input structures,
because input structures disappear before the errors are printed, so it
means that we can try to access through a NULL pointer.

Small fix in newline() and addinput() clarification by quinq.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -352,8 +352,8 @@
 
 struct input {
 	char flags;
-	unsigned short nline;
-	char *fname;
+	unsigned lineno;
+	char *filenam;
 	FILE *fp;
 	Symbol *hide;
 	char *line, *begin, *p;
@@ -406,6 +406,7 @@
 extern void delinput(void);
 extern void setsafe(int type);
 extern void ilex(void);
+extern int setloc(char *fname, unsigned line);
 #define accept(t) ((yytoken == (t)) ? next() : 0)
 
 /* code.c */
@@ -458,6 +459,8 @@
 extern unsigned curctx;
 extern Symbol *curfun, *zero, *one;
 extern char *infile, *outfile;
+unsigned lineno;
+char filenam[FILENAME_MAX];
 
 extern Type *voidtype, *pvoidtype, *booltype,
             *uchartype,   *chartype, *schartype,
--- a/cc1/cpp.c
+++ b/cc1/cpp.c
@@ -34,8 +34,8 @@
 	def = xmalloc(strlen(fmt) + strlen(macro) + strlen(val));
 
 	sprintf(def, fmt, macro, val);
+	lineno = ++ncmdlines;
 	addinput(source, &dummy, def);
-	input->nline = ++ncmdlines;
 	cpp();
 	delinput();
 }
@@ -254,11 +254,11 @@
 
 	macroname = sym->name;
 	if (sym == symfile) {
-		elen = sprintf(buffer, "\"%s\" ", input->fname);
+		elen = sprintf(buffer, "\"%s\" ", filenam);
 		goto substitute;
 	}
 	if (sym == symline) {
-		elen = sprintf(buffer, "%d ", input->nline);
+		elen = sprintf(buffer, "%d ", lineno);
 		goto substitute;
 	}
 	if (!s)
@@ -275,7 +275,7 @@
 substitute:
 	DBG("MACRO '%s' expanded to :'%s'", macroname, buffer);
 	buffer[elen] = '\0';
-	addinput(input->fname, sym, xstrdup(buffer));
+	addinput(filenam, sym, xstrdup(buffer));
 
 	return 1;
 }
@@ -448,7 +448,7 @@
 static char *
 cwd(char *buf)
 {
-	char *p, *s = input->fname;
+	char *p, *s = filenam;
 	size_t len;
 
 	if ((p = strrchr(s, '/')) == NULL)
@@ -538,7 +538,7 @@
 line(void)
 {
 	long n;
-	char *endp;
+	char *endp, *fname;
 
 	if (cppoff)
 		return;
@@ -552,20 +552,18 @@
 	}
 
 	next();
-	if (yytoken == EOFTOK)
-		goto set_line;
-
-	if (*yytext != '\"' || yylen == 1) {
-		cpperror("second parameter of #line is not a valid filename");
-		return;
+	if (yytoken == '\n') {
+		fname = NULL;
+	} else {
+		if (*yytext != '\"' || yylen == 1) {
+			cpperror("second parameter of #line is not a valid filename");
+			return;
+		}
+		fname = yylval.sym->u.s;
 	}
-
-	free(input->fname);
-	input->fname = xstrdup(yylval.sym->u.s);
-	next();
-
-set_line:
-	input->nline = n - 1;
+	setloc(fname, n - 1);
+	if (yytoken != '\n')
+		next();
 }
 
 static void
--- a/cc1/error.c
+++ b/cc1/error.c
@@ -18,7 +18,7 @@
 	if (flag == 0)
 		return;
 	fprintf(stderr, "%s:%u: %s: ",
-	       input->fname, input->nline,
+	       filenam, lineno,
 	       (flag < 0) ? "error" : "warning");
 	vfprintf(stderr, fmt, va);
 	putc('\n', stderr);
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -18,6 +18,8 @@
 char yytext[STRINGSIZ+3];
 unsigned short yylen;
 int lexmode = CCMODE;
+unsigned lineno;
+char filenam[FILENAME_MAX];
 
 int namespace = NS_IDEN;
 static int safe;
@@ -69,17 +71,31 @@
 }
 
 int
+setloc(char *fname, unsigned line)
+{
+	size_t len;
+
+	if ((len = strlen(fname)) >= FILENAME_MAX)
+		die("file name too long: '%s'", fname);
+	memcpy(filenam, fname, len);
+	filenam[len] = '\0';
+
+	free(input->filenam);
+	input->filenam = xstrdup(fname);
+	lineno = input->lineno = line;
+	return 1;
+}
+
+int
 addinput(char *fname, Symbol *hide, char *buffer)
 {
 	FILE *fp;
-	unsigned flags, nline = 0;
-	Input *ip;
+	unsigned flags;
+	Input *newip, *curip = input;
 
 	if (hide) {
 		/* this is a macro expansion */
 		fp = NULL;
-		if (input)
-			nline = input->nline;
 		if (hide->hide == UCHAR_MAX)
 			die("Too many macro expansions");
 		++hide->hide;
@@ -87,9 +103,9 @@
 	} else  if (fname) {
 		/* a new file */
 		if ((fp = fopen(fname, "r")) == NULL)
-			return 0;
+			die("Error opening '%s': %s", fname, strerror(errno));
 		flags = IFILE;
-		if (input && onlyheader)
+		if (curip && onlyheader)
 			printf("%s: %s\n", infile, fname);
 	} else {
 		/* reading from stdin */
@@ -98,7 +114,7 @@
 		flags = ISTDIN;
 	}
 
-	ip = xmalloc(sizeof(*ip));
+	newip = xmalloc(sizeof(*newip));
 
 	if (!buffer) {
 		buffer = xmalloc(INPUTSIZ);
@@ -105,16 +121,19 @@
 		buffer[0] = '\0';
 	}
 
-	ip->p = ip->begin = ip->line = buffer;
-	ip->fname = xstrdup(fname);
-	ip->next = input;
-	ip->fp = fp;
-	ip->hide = hide;
-	ip->nline = nline;
-	ip->flags = flags;
-	input = ip;
+	if (curip)
+		curip->lineno = lineno;
 
-	return 1;
+	newip->p = newip->begin = newip->line = buffer;
+	newip->filenam = NULL;
+	newip->lineno = 0;
+	newip->next = curip;
+	newip->fp = fp;
+	newip->hide = hide;
+	newip->flags = flags;
+	input = newip;
+
+	return setloc(fname, (curip) ? curip->lineno : newip->lineno);
 }
 
 void
@@ -127,7 +146,7 @@
 	case IFILE:
 		if (fclose(ip->fp))
 			die("error: failed to read from input file '%s'",
-			    ip->fname);
+			    ip->filenam);
 		break;
 	case IMACRO:
 		assert(hide->hide == 1);
@@ -135,15 +154,19 @@
 		break;
 	}
 	input = ip->next;
-	free(ip->fname);
+	free(ip->filenam);
 	free(ip->line);
+	if (input) {
+		lineno = input->lineno;
+		strcpy(filenam, input->filenam);
+	}
 }
 
 static void
 newline(void)
 {
-	if (++input->nline == 0)
-		die("error: input file '%s' too long", input->fname);
+	if (++lineno == 0)
+		die("error: input file '%s' too long", filenam);
 }
 
 /*
@@ -280,15 +303,15 @@
 		char *s;
 
 		putchar('\n');
-		if (strcmp(file, input->fname)) {
-			strcpy(file, input->fname);
+		if (strcmp(file, filenam)) {
+			strcpy(file, filenam);
 			s = "#line %u %s\n";
-		} else if (nline+1 != input->nline) {
+		} else if (nline+1 != lineno) {
 			s = "#line %u\n";
 		} else {
 			s = "";
 		}
-		nline = input->nline;
+		nline = lineno;
 		printf(s, nline, file);
 	}
 	return 1;