From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mimir.eigenstate.org ([206.124.132.107]) by ewsd; Thu Oct 15 21:41:05 -0400 2020 Received: from abbatoir.fios-router.home (pool-74-101-2-6.nycmny.fios.verizon.net [74.101.2.6]) by mimir.eigenstate.org (OpenSMTPD) with ESMTPSA id c08ae310 (TLSv1.2:ECDHE-RSA-AES256-SHA:256:NO) for <9front@9front.org>; Thu, 15 Oct 2020 18:40:54 -0700 (PDT) Message-ID: <71CE86A5EC086742886B6A2E7F09C255@eigenstate.org> To: 9front@9front.org Subject: rc: null list in concatenation line numbers Date: Thu, 15 Oct 2020 18:40:53 -0700 From: ori@eigenstate.org MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: CSS metadata framework CMS database This change causes rc to print the line number of an error within Xerror(), meaning that the feared 'null list in concatenation' will now tell you from where it came, like so: stdin:10: null test.rc:6: null list in concatenation This change works by adding a bytecode instruction to our code which updates a location. In the interests of not bloating the bytecode too much, the new Xloc instruction packs both the line number and file into one integer, which limits us to 2048 filenames and 1 million lines per file. Hitting these limits won't break scripts, but they will turn the location information into garbage. I think this is acceptable: if you source thousands of files, you deserve it. I also failed to resist temptation to clean up some style annoyances -- lack of 'extern' on variables, inconsistent repetition of typedef'ed tags, and some useless casts from malloc, so this patch is a bit noisier than it could be. Testing and review welcome. diff -r e05e4b6c6546 sys/src/cmd/rc/code.c --- a/sys/src/cmd/rc/code.c Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/code.c Thu Oct 15 18:39:30 2020 -0700 @@ -6,10 +6,12 @@ #define c0 t->child[0] #define c1 t->child[1] #define c2 t->child[2] +code *codebuf; int codep, ncode; #define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++) #define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++) #define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++) + void stuffdot(int); char *fnstr(tree*); void outcode(tree*, int); @@ -37,9 +39,9 @@ int compile(tree *t) { + codep = 0; ncode = 100; - codebuf = (code *)emalloc(ncode*sizeof codebuf[0]); - codep = 0; + codebuf = emalloc(ncode*sizeof codebuf[0]); emiti(0); /* reference count */ outcode(t, flag['e']?1:0); if(nerror){ @@ -79,12 +81,28 @@ void outcode(tree *t, int eflag) { - int p, q; + static int file, line; + int p, q, f, l; tree *tt; if(t==0) return; if(t->type!=NOT && t->type!=';') runq->iflast = 0; + if(t->file != file || t->line != line){ + file = t->file; + line = t->line; + + /* + * These are small enough that with a ton of sourcing, + * overflow is a realistic risk. If we run out of files, + * set to file 0, which is always '???' + */ + f = (t->file > LFMAX) ? 0 : t->file << LSHIFT; + l = (t->line > LMASK) ? -1 : t->line; + + emitf(Xloc); + emiti(f|l); + } switch(t->type){ default: pfmt(err, "bad type %d in outcode\n", t->type); diff -r e05e4b6c6546 sys/src/cmd/rc/exec.c --- a/sys/src/cmd/rc/exec.c Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/exec.c Thu Oct 15 18:39:30 2020 -0700 @@ -14,6 +14,7 @@ struct thread *p = new(struct thread); p->code = codecopy(c); + p->loc = 0; p->pc = pc; p->argv = 0; p->redir = p->startredir = runq?runq->redir:0; @@ -205,6 +206,11 @@ pushlist(); argv0 = estrdup(argv[0]); for(i = argc-1;i!=0;--i) pushword(argv[i]); + + lexpath = erealloc(lexpath, sizeof(char*)); + nlexpath = 1; + lexpath[0] = strdup("???"); + for(;;){ if(flag['r']) pfnc(err, runq); @@ -953,10 +959,15 @@ void Xerror(char *s) { + int f, l; + + f = runq->loc >> LSHIFT; + l = runq->loc & LMASK; + assert(f >= 0 && f < nlexpath); if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) - pfmt(err, "rc: %s: %r\n", s); + pfmt(err, "rc:%d: %s: %r\n", l, s); else - pfmt(err, "rc (%s): %s: %r\n", argv0, s); + pfmt(err, "%s:%d: %s: %r\n", lexpath[f], l, s); flush(err); setstatus("error"); while(!runq->iflag) Xreturn(); @@ -965,10 +976,15 @@ void Xerror1(char *s) { + int f, l; + + f = runq->loc >> LSHIFT; + l = runq->loc & LMASK; + assert(f >= 0 && f < nlexpath); if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) - pfmt(err, "rc: %s\n", s); + pfmt(err, "rc:%d: %s\n", l, s); else - pfmt(err, "rc (%s): %s\n", argv0, s); + pfmt(err, "%s:%d: %s\n", lexpath[f], l, s); flush(err); setstatus("error"); while(!runq->iflag) Xreturn(); @@ -1025,3 +1041,10 @@ { globlist(runq->argv->words); } + +void +Xloc(void) +{ + runq->loc = runq->code[runq->pc].i; + runq->pc++; +} diff -r e05e4b6c6546 sys/src/cmd/rc/exec.h --- a/sys/src/cmd/rc/exec.h Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/exec.h Thu Oct 15 18:39:30 2020 -0700 @@ -5,7 +5,7 @@ extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(void), Xdup(void); extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void); extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void); -extern void Xrdwr(void); +extern void Xrdwr(void), Xloc(void); extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); extern void Xtrue(void), Xword(void), Xglobs(void), Xwrite(void), Xpipefd(void), Xcase(void); extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void); @@ -30,7 +30,7 @@ struct redir{ char type; /* what to do */ short from, to; /* what to do it to */ - struct redir *next; /* what else to do (reverse order) */ + redir *next; /* what else to do (reverse order) */ }; #define NSTATUS ERRMAX /* length of status (from plan 9) */ /* @@ -40,14 +40,15 @@ #define RDUP 2 /* dup2(from, to); */ #define RCLOSE 3 /* close(from); */ struct thread{ - union code *code; /* code for this thread */ + code *code; /* code for this thread */ int pc; /* code[pc] is the next instruction */ - struct list *argv; /* argument stack */ - struct redir *redir; /* redirection stack */ - struct redir *startredir; /* redir inheritance point */ - struct var *local; /* list of local variables */ + int loc; /* source code location */ + list *argv; /* argument stack */ + redir *redir; /* redirection stack */ + redir *startredir; /* redir inheritance point */ + var *local; /* list of local variables */ char *cmdfile; /* file name in Xrdcmd */ - struct io *cmdfd; /* file descriptor for Xrdcmd */ + io *cmdfd; /* file descriptor for Xrdcmd */ int iflast; /* static `if not' checking */ int eof; /* is cmdfd at eof? */ int iflag; /* interactive? */ @@ -55,7 +56,7 @@ int pid; /* process for Xpipewait to wait for */ char status[NSTATUS]; /* status for Xpipewait */ tree *treenodes; /* tree nodes created by this process */ - thread *ret; /* who continues when this finishes */ + thread *ret; /* who continues when this finishes */ }; thread *runq; code *codecopy(code*); diff -r e05e4b6c6546 sys/src/cmd/rc/lex.c --- a/sys/src/cmd/rc/lex.c Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/lex.c Thu Oct 15 18:39:30 2020 -0700 @@ -25,6 +25,13 @@ int doprompt = 1; int inquote; int incomm; +int lastc; +int ndot; +int nerror; +int lexline; +int lexfile; +char **lexpath; +int nlexpath; /* * Look ahead in the input stream */ @@ -39,13 +46,14 @@ /* * Consume the lookahead character. */ - int advance(void) { int c = nextc(); lastc = future; future = EOF; + if(c == '\n') + lexline++; return c; } /* diff -r e05e4b6c6546 sys/src/cmd/rc/pfnc.c --- a/sys/src/cmd/rc/pfnc.c Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/pfnc.c Thu Oct 15 18:39:30 2020 -0700 @@ -51,6 +51,7 @@ Xrdfn, "Xrdfn", Xsimple, "Xsimple", Xqw, "Xqw", + Xloc, "Xloc", 0}; void diff -r e05e4b6c6546 sys/src/cmd/rc/rc.h --- a/sys/src/cmd/rc/rc.h Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/rc.h Thu Oct 15 18:39:30 2020 -0700 @@ -43,6 +43,8 @@ char *str; int quoted; int iskw; + int file; + int line; tree *child[3]; tree *next; }; @@ -54,6 +56,19 @@ tree *simplemung(tree*), *heredoc(tree*); void freetree(tree*); tree *cmdtree; + +/* + * Locations are stored as instructions in the rc bytecode. + * To avoid wasting too much space, both the file and line + * is packed into a single integer, as + * (file << LSHIFT) | line + * With 32 bit integers, this gives us 2048 filenames, with + * just over 1 million lines of code in each. + */ +#define LSHIFT 20 +#define LMASK ((1<code[runq->pc]; + code *c=&runq->code[runq->pc]; while(c->f==Xpopredir || c->f==Xunlocal) c++; return c->f==Xexit; } @@ -294,7 +294,7 @@ execdot(void) { int iflag = 0; - int fd; + int fd, i; list *av; thread *p = runq; char *zero, *file; @@ -354,6 +354,20 @@ Xerror(".: can't open"); return; } + + lexline = 1; + for(i = 0; i < nlexpath; i++){ + if(strcmp(lexpath[i], zero) == 0){ + lexfile = i; + break; + } + } + if(i == nlexpath){ + lexpath = erealloc(lexpath, (nlexpath + 1)*sizeof(char*)); + lexpath[nlexpath] = estrdup(zero); + lexfile = nlexpath; + nlexpath++; + } /* set up for a new command loop */ start(dotcmds, 1, (struct var *)0); pushredir(RCLOSE, fd, 0); diff -r e05e4b6c6546 sys/src/cmd/rc/tree.c --- a/sys/src/cmd/rc/tree.c Mon Oct 12 02:03:52 2020 +0200 +++ b/sys/src/cmd/rc/tree.c Thu Oct 15 18:39:30 2020 -0700 @@ -16,6 +16,8 @@ t->str = 0; t->child[0] = t->child[1] = t->child[2] = 0; t->next = treenodes; + t->file = lexfile; + t->line = lexline; treenodes = t; return t; }