make can confuse cpp
Steve Summit
stevesu at copper.UUCP
Wed Nov 5 04:37:17 AEST 1986
Description:
Under suitably obscure circumstances, make invokes
processes with standard input closed. Marginal coding
practices in cpp can't handle this situation.
Repeat-By:
Use make -f -. For instance, if the file m contains
x.o: x.c
then we can do
$ touch x.c
$ make -f - < m
cc -c x.c
x.c: 0: No source file /tmp/ctma3348
*** Error code 1
Stop.
$
The problem is cpp's file-processing algorithm, which is
as follows:
1. Set the input file descriptor (fin) to
standard input (0).
2. If there is a command line filename, open it,
setting fin to the resulting file descriptor.
3. If there is a second command line filename,
indicated by fin being nonzero, open it as the
output file.
Therefore, if cpp is invoked with the standard input
closed, the first command line filename will be opened,
but will end up on file descriptor 0, so that when the
second command line argument is seen, it will look as if
no command line argument was seen, and an attempt will be
made to open the second one for input.
Some time ago, there was a discussion on net.unix-wizards
on why daemons always opened up file descriptors 0, 1,
and 2 on /dev/null. Here's one more reason: it's
easy to write apparently reasonable programs which fail
if an open returns a file descriptor less than 3.
By the way, if you fix cpp but not make, you may
discover that the assembler appears to have a similar
problem, which I haven't fixed.
Fix:
Here are fixes for both make and cpp.
The fixed make will only close the Makefile file
descriptor if make opened it (if it wasn't standard
input). When make -f - is used, this has the effect that
the processes forked by make all have their standard
input opened on the Makefile, which is at EOF. It is
arguable that make should reopen standard input on
/dev/null in this case:
if(! unequal(descfile, "-")) {
r = rdd1(stdin);
(void)fclose(stdin);
(void)open("/dev/null", 0); /* better return 0 */
return(r);
}
The fix for cpp is to use an explicit binary flag to keep
track of whether an input filename has been seen, rather
than trying to intuit it from the state of fin.
Interestingly enough, the mysterious comment inside the
#ifndef gcos in cpp.c, that John couldn't figure out, may
reflect the same problem.
*** main.c Thu Sep 1 16:52:16 1983
--- main.new.c Mon Nov 3 12:10:32 1986
***************
*** 275,280
char *descfile;
{
FILE * k;
/* read and parse description */
--- 275,281 -----
char *descfile;
{
FILE * k;
+ int r;
/* read and parse description */
***************
*** 303,310
if(! unequal(descfile, "-"))
return( rdd1(stdin) );
! if( (k = fopen(descfile,"r")) != NULL)
! return( rdd1(k) );
return(1);
}
--- 304,314 -----
if(! unequal(descfile, "-"))
return( rdd1(stdin) );
! if( (k = fopen(descfile,"r")) != NULL) {
! r = rdd1(k);
! (void)fclose(k);
! return(r);
! }
return(1);
}
***************
*** 324,332
if( yyparse() )
fatal("Description file error");
-
- if(fin != NULL)
- fclose(fin);
return(0);
}
--- 328,333 -----
if( yyparse() )
fatal("Description file error");
return(0);
}
*** cpp.c Thu May 16 16:41:24 1985
--- cpp.new.c Mon Nov 3 12:31:28 1986
***************
*** 1019,1024
register int i,c;
register char *p;
char *tf,**cp2;
# if gcos
if (setjmp(env)) return (exfail);
--- 1019,1025 -----
register int i,c;
register char *p;
char *tf,**cp2;
+ int seeninput = 0;
# if gcos
if (setjmp(env)) return (exfail);
***************
*** 1112,1118
continue;
}
default:
! if (fin==STDIN) {
if (0>(fin=open(argv[i], READ))) {
pperror("No source file %s",argv[i]); exit(8);
}
--- 1113,1119 -----
continue;
}
default:
! if (!seeninput) {
if (0>(fin=open(argv[i], READ))) {
pperror("No source file %s",argv[i]); exit(8);
}
***************
*** 1116,1125
if (0>(fin=open(argv[i], READ))) {
pperror("No source file %s",argv[i]); exit(8);
}
fnames[ifno]=copy(argv[i]);
dirs[0]=dirnams[ifno]=trmdir(argv[i]);
# ifndef gcos
/* too dangerous to have file name in same syntactic position
be input or output file depending on file redirections,
so force output to stdout, willy-nilly
[i don't see what the problem is. jfr]
--- 1117,1127 -----
if (0>(fin=open(argv[i], READ))) {
pperror("No source file %s",argv[i]); exit(8);
}
fnames[ifno]=copy(argv[i]);
dirs[0]=dirnams[ifno]=trmdir(argv[i]);
+ seeninput = 1;
# ifndef gcos
/* too dangerous to have file name in same syntactic position
be input or output file depending on file redirections,
so force output to stdout, willy-nilly
[i don't see what the problem is. jfr]
More information about the Comp.bugs.4bsd.ucb-fixes
mailing list