Put the big block of code that was common to ParseDoInclude() and

ParseTraditionalInclude() into a separate routine.
Fix the 'use after free' and 'free on item not malloced' that got added
to ParseTraditionalInclude() in Feb 2006 (rev 1.111).
Kill the 'PTR' struct and put both its members into IFile.
Remove the parameter from ParseEOF(), 1 of the 3 calls passed the wrong value!
Fortunately another test stopped anything nasty happening, we'll use that
test instead.
This commit is contained in:
dsl 2006-12-07 21:07:01 +00:00
parent f45632428c
commit a294d83a63
1 changed files with 87 additions and 196 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: parse.c,v 1.122 2006/12/04 21:34:47 dsl Exp $ */
/* $NetBSD: parse.c,v 1.123 2006/12/07 21:07:01 dsl Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -69,14 +69,14 @@
*/
#ifndef MAKE_NATIVE
static char rcsid[] = "$NetBSD: parse.c,v 1.122 2006/12/04 21:34:47 dsl Exp $";
static char rcsid[] = "$NetBSD: parse.c,v 1.123 2006/12/07 21:07:01 dsl Exp $";
#else
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
#else
__RCSID("$NetBSD: parse.c,v 1.122 2006/12/04 21:34:47 dsl Exp $");
__RCSID("$NetBSD: parse.c,v 1.123 2006/12/07 21:07:01 dsl Exp $");
#endif
#endif /* not lint */
#endif
@ -91,8 +91,8 @@ __RCSID("$NetBSD: parse.c,v 1.122 2006/12/04 21:34:47 dsl Exp $");
* module.
*
* Most important structures are kept in Lsts. Directories for
* the #include "..." function are kept in the 'parseIncPath' Lst, while
* those for the #include <...> are kept in the 'sysIncPath' Lst. The
* the .include "..." function are kept in the 'parseIncPath' Lst, while
* those for the .include <...> are kept in the 'sysIncPath' Lst. The
* targets currently being defined are kept in the 'targets' Lst.
*
* The variables 'fname' and 'lineno' are used to track the name
@ -148,11 +148,6 @@ static Lst targCmds; /* command lines for targets */
#endif
static Boolean inLine; /* true if currently in a dependency
* line or its commands */
typedef struct {
char *str;
char *ptr;
} PTR;
static int fatals = 0;
static GNode *mainNode; /* The main target to create. This is the
@ -161,8 +156,9 @@ static GNode *mainNode; /* The main target to create. This is the
typedef struct IFile {
const char *fname; /* name of file */
int lineno; /* line number in file */
FILE * F; /* the open stream */
PTR * P; /* the char pointer */
FILE *F; /* the open stream */
char *P_str; /* point to base of string buffer */
char *P_ptr; /* point to next char of string buffer */
} IFile;
static IFile curFile;
@ -172,8 +168,7 @@ static IFile curFile;
* Definitions for handling #include specifications
*/
static Lst includes; /* stack of IFiles generated by
* #includes */
static Lst includes; /* stack of IFiles generated by .includes */
Lst parseIncPath; /* list of directories for "..." includes */
Lst sysIncPath; /* list of directories for <...> includes */
Lst defIncPath; /* default directories for <...> includes */
@ -301,7 +296,7 @@ static void ParseSetParseFile(const char *);
#ifdef SYSVINCLUDE
static void ParseTraditionalInclude(char *);
#endif
static int ParseEOF(int);
static int ParseEOF(void);
static char *ParseReadLine(void);
static char *ParseSkipLine(int, int);
static void ParseFinishLine(void);
@ -1733,63 +1728,12 @@ Parse_AddIncludeDir(char *dir)
* fname and curFILE are altered for the new file
*---------------------------------------------------------------------
*/
static void
ParseDoInclude(char *line)
Parse_include_file(char *file, Boolean isSystem, int silent)
{
char *fullname; /* full pathname of file */
IFile *oldFile; /* state associated with current file */
char endc; /* the character which ends the file spec */
char *cp; /* current position in file spec */
Boolean isSystem; /* TRUE if makefile is a system makefile */
int silent = (*line != 'i') ? 1 : 0;
char *file = &line[7 + silent];
/*
* Skip to delimiter character so we know where to look
*/
while ((*file == ' ') || (*file == '\t')) {
file++;
}
if ((*file != '"') && (*file != '<')) {
Parse_Error(PARSE_FATAL,
".include filename must be delimited by '\"' or '<'");
return;
}
/*
* Set the search path on which to find the include file based on the
* characters which bracket its name. Angle-brackets imply it's
* a system Makefile while double-quotes imply it's a user makefile
*/
if (*file == '<') {
isSystem = TRUE;
endc = '>';
} else {
isSystem = FALSE;
endc = '"';
}
/*
* Skip to matching delimiter
*/
for (cp = ++file; *cp && *cp != endc; cp++) {
continue;
}
if (*cp != endc) {
Parse_Error(PARSE_FATAL,
"Unclosed %cinclude filename. '%c' expected",
'.', endc);
return;
}
*cp = '\0';
/*
* Substitute for any variables in the file name before trying to
* find the thing.
*/
file = Var_Subst(NULL, file, VAR_CMD, FALSE);
/*
* Now we know the file's name and its search path, we attempt to
@ -1849,18 +1793,16 @@ ParseDoInclude(char *line)
/*
* Look for it on the system path
*/
fullname = Dir_FindFile(file, Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
fullname = Dir_FindFile(file,
Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
}
if (fullname == NULL) {
*cp = endc;
if (!silent)
Parse_Error(PARSE_FATAL, "Could not find %s", file);
return;
}
free(file);
/*
* Once we find the absolute path to the file, we get to save all the
* state from the current file before we can start reading this
@ -1886,7 +1828,7 @@ ParseDoInclude(char *line)
ParseSetParseFile(curFile.fname);
curFile.F = fopen(fullname, "r");
curFile.P = NULL;
curFile.P_str = curFile.P_ptr = NULL;
if (curFile.F == (FILE * ) NULL) {
if (!silent)
@ -1894,10 +1836,61 @@ ParseDoInclude(char *line)
/*
* Pop to previous file
*/
(void)ParseEOF(0);
(void)ParseEOF();
}
}
static void
ParseDoInclude(char *line)
{
char endc; /* the character which ends the file spec */
char *cp; /* current position in file spec */
int silent = (*line != 'i') ? 1 : 0;
char *file = &line[7 + silent];
/* Skip to delimiter character so we know where to look */
while (*file == ' ' || *file == '\t')
file++;
if (*file != '"' && *file != '<') {
Parse_Error(PARSE_FATAL,
".include filename must be delimited by '\"' or '<'");
return;
}
/*
* Set the search path on which to find the include file based on the
* characters which bracket its name. Angle-brackets imply it's
* a system Makefile while double-quotes imply it's a user makefile
*/
if (*file == '<') {
endc = '>';
} else {
endc = '"';
}
/* Skip to matching delimiter */
for (cp = ++file; *cp && *cp != endc; cp++)
continue;
if (*cp != endc) {
Parse_Error(PARSE_FATAL,
"Unclosed %cinclude filename. '%c' expected",
'.', endc);
return;
}
*cp = '\0';
/*
* Substitute for any variables in the file name before trying to
* find the thing.
*/
file = Var_Subst(NULL, file, VAR_CMD, FALSE);
Parse_include_file(file, endc == '>', silent);
free(file);
}
/*-
*---------------------------------------------------------------------
@ -1963,8 +1956,7 @@ Parse_FromString(char *str, int lineno)
(void)Lst_AtFront(includes, oldFile);
curFile.F = NULL;
curFile.P = emalloc(sizeof(PTR));
curFile.P->str = curFile.P->ptr = str;
curFile.P_str = curFile.P_ptr = str;
curFile.lineno = lineno;
curFile.fname = curFile.fname;
}
@ -1990,18 +1982,11 @@ Parse_FromString(char *str, int lineno)
static void
ParseTraditionalInclude(char *line)
{
char *fullname; /* full pathname of file */
IFile *oldFile; /* state associated with current file */
char *cp; /* current position in file spec */
char *prefEnd;
int done = 0;
int silent = (line[0] != 'i') ? 1 : 0;
char *file = &line[silent + 7];
const char *cfname;
size_t clineno;
cfname = curFile.fname;
clineno = curFile.lineno;
char *all_files;
if (DEBUG(PARSE)) {
fprintf(debug_file, "ParseTraditionalInclude: %s\n", file);
@ -2017,7 +2002,7 @@ ParseTraditionalInclude(char *line)
* Substitute for any variables in the file name before trying to
* find the thing.
*/
file = Var_Subst(NULL, file, VAR_CMD, FALSE);
all_files = Var_Subst(NULL, file, VAR_CMD, FALSE);
if (*file == '\0') {
Parse_Error(PARSE_FATAL,
@ -2025,10 +2010,8 @@ ParseTraditionalInclude(char *line)
return;
}
for (; !done; file = cp + 1) {
/*
* Skip to end of line or next whitespace
*/
for (file = all_files; !done; file = cp + 1) {
/* Skip to end of line or next whitespace */
for (cp = file; *cp && !isspace((unsigned char) *cp); cp++)
continue;
@ -2037,99 +2020,9 @@ ParseTraditionalInclude(char *line)
else
done = 1;
/*
* Now we know the file's name, we attempt to find the durn thing.
* A return of NULL indicates the file don't exist.
*
* Include files are first searched for relative to the including
* file's location. We don't want to cd there, of course, so we
* just tack on the old file's leading path components and call
* Dir_FindFile to see if we can locate the beast.
* XXX - this *does* search in the current directory, right?
*/
prefEnd = strrchr(cfname, '/');
if (prefEnd != NULL) {
char *newName;
*prefEnd = '\0';
newName = str_concat(cfname, file, STR_ADDSLASH);
fullname = Dir_FindFile(newName, parseIncPath);
if (fullname == NULL) {
fullname = Dir_FindFile(newName, dirSearchPath);
}
free(newName);
*prefEnd = '/';
} else {
fullname = NULL;
}
if (fullname == NULL) {
/*
* System makefile or makefile wasn't found in same directory as
* included makefile. Search for it first on the -I search path,
* then on the .PATH search path, if not found in a
* -I directory. XXX: Suffix specific?
*/
fullname = Dir_FindFile(file, parseIncPath);
if (fullname == NULL) {
fullname = Dir_FindFile(file, dirSearchPath);
}
}
if (fullname == NULL) {
/*
* Still haven't found the makefile. Look for it on the system
* path as a last resort.
*/
fullname = Dir_FindFile(file,
Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath);
}
if (fullname == NULL) {
if (!silent)
ParseErrorInternal(cfname, clineno, PARSE_FATAL,
"Could not find %s", file);
free(file);
continue;
}
free(file);
/*
* Once we find the absolute path to the file, we get to save all
* the state from the current file before we can start reading this
* include file. The state is stored in an IFile structure which
* is placed on a list with other IFile structures. The list makes
* a very nice stack to track how we got here...
*/
oldFile = emalloc(sizeof(IFile));
memcpy(oldFile, &curFile, sizeof(IFile));
(void)Lst_AtFront(includes, oldFile);
/*
* Once the previous state has been saved, we can get down to
* reading the new file. We set up the name of the file to be the
* absolute name of the include file so error messages refer to the
* right place. Naturally enough, we start reading at line number 0.
*/
curFile.fname = fullname;
curFile.lineno = 0;
curFile.F = fopen(fullname, "r");
curFile.P = NULL;
if (curFile.F == NULL) {
if (!silent)
ParseErrorInternal(cfname, clineno, PARSE_FATAL,
"Cannot open %s", fullname);
/*
* Pop to previous file
*/
(void)ParseEOF(1);
}
Parse_include_file(file, FALSE, silent);
}
free(all_files);
}
#endif
@ -2149,27 +2042,25 @@ ParseTraditionalInclude(char *line)
*---------------------------------------------------------------------
*/
static int
ParseEOF(int opened)
ParseEOF(void)
{
IFile *ifile; /* the state on the top of the includes stack */
/* XXX dispose of curFile info */
/* Leak curFile.fname because all the gnodes have pointers to it */
if (curFile.F)
(void)fclose(curFile.F);
free(curFile.P_str);
if (Lst_IsEmpty(includes)) {
Var_Delete(".PARSEDIR", VAR_GLOBAL);
Var_Delete(".PARSEFILE", VAR_GLOBAL);
memset(&curFile, 0, sizeof curFile);
return (DONE);
}
ifile = (IFile *)Lst_DeQueue(includes);
/* XXX dispose of curFile info */
/* Leak curFile.fname because all the gnodes have pointers to it */
if (opened && curFile.F)
(void)fclose(curFile.F);
if (curFile.P) {
free(curFile.P->str);
free(curFile.P);
}
memcpy(&curFile, ifile, sizeof(IFile));
free(ifile);
@ -2196,8 +2087,8 @@ ParseReadc(void)
if (curFile.F)
return fgetc(curFile.F);
if (curFile.P && *curFile.P->ptr)
return *curFile.P->ptr++;
if (*curFile.P_ptr)
return *curFile.P_ptr++;
return EOF;
}
@ -2220,8 +2111,8 @@ ParseUnreadc(int c)
ungetc(c, curFile.F);
return;
}
if (curFile.P) {
*--(curFile.P->ptr) = c;
if (curFile.P_ptr) {
*--curFile.P_ptr = c;
return;
}
}
@ -2750,7 +2641,7 @@ Parse_File(const char *name, FILE *stream)
/*
* Reached EOF, but it may be just EOF of an include file...
*/
} while (ParseEOF(1) == CONTINUE);
} while (ParseEOF() == CONTINUE);
/*
* Make sure conditionals are clean