]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/acid/exec.c
acid: fix memory corruption due to gc
[plan9front.git] / sys / src / cmd / acid / exec.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <mach.h>
6 #define Extern extern
7 #include "acid.h"
8
9 void
10 error(char *fmt, ...)
11 {
12         int i;
13         char buf[2048];
14         va_list arg;
15
16         /* Unstack io channels */
17         if(iop != 0) {
18                 for(i = 1; i < iop; i++)
19                         Bterm(io[i]);
20                 bout = io[0];
21                 iop = 0;
22         }
23
24         ret = 0;
25         gotint = 0;
26         Bflush(bout);
27         if(silent)
28                 silent = 0;
29         else {
30                 va_start(arg, fmt);
31                 vseprint(buf, buf+sizeof(buf), fmt, arg);
32                 va_end(arg);
33                 fprint(2, "%L: (error) %s\n", buf);
34         }
35         while(popio())
36                 ;
37         interactive = 1;
38         longjmp(err, 1);
39 }
40
41 void
42 unwind(void)
43 {
44         int i;
45         Lsym *s;
46         Value *v;
47
48         for(i = 0; i < Hashsize; i++) {
49                 for(s = hash[i]; s; s = s->hash) {
50                         while(s->v->pop) {
51                                 v = s->v->pop;
52                                 free(s->v);
53                                 s->v = v;
54                         }
55                 }
56         }
57 }
58
59 void
60 execrec(Node *n)
61 {
62         Value *v;
63         Lsym *s;
64
65         /* make node a root so it isn't collected! */
66         s = mkvar("_thiscmd");
67
68         v = gmalloc(sizeof(Value));
69         memset(v, 0, sizeof(Value));
70         v->type = TCODE;
71         v->cc = n;
72         v->pop = s->v;
73
74         s->v = v;
75         s->proc = n;
76
77         gc();
78         execute(n);
79
80         s->proc = s->v->cc;
81         s->v = v->pop;
82         free(v);
83 }
84
85 void
86 execute(Node *n)
87 {
88         Value *v;
89         Lsym *sl;
90         Node *l, *r;
91         vlong i, s, e;
92         Node res, xx;
93         static int stmnt;
94
95         if(gotint)
96                 error("interrupted");
97
98         if(n == 0)
99                 return;
100
101         if(stmnt++ > 5000) {
102                 Bflush(bout);
103                 stmnt = 0;
104         }
105
106         l = n->left;
107         r = n->right;
108
109         switch(n->op) {
110         default:
111                 expr(n, &res);
112                 if(ret || (res.type == TLIST && res.l == 0 && n->op != OADD))
113                         break;
114                 prnt->right = &res;
115                 expr(prnt, &xx);
116                 break;
117         case OASGN:
118         case OCALL:
119                 expr(n, &res);
120                 break;
121         case OCOMPLEX:
122                 decl(n);
123                 break;
124         case OLOCAL:
125                 for(n = n->left; n; n = n->left) {
126                         if(ret == 0)
127                                 error("local not in function");
128                         sl = n->sym;
129                         if(sl->v->ret == ret)
130                                 error("%s declared twice", sl->name);
131                         v = gmalloc(sizeof(Value));
132                         v->ret = ret;
133                         v->pop = sl->v;
134                         sl->v = v;
135                         v->scope = 0;
136                         *(ret->tail) = sl;
137                         ret->tail = &v->scope;
138                         v->set = 0;
139                 }
140                 break;
141         case ORET:
142                 if(ret == 0)
143                         error("return not in function");
144                 expr(n->left, ret->val);
145                 longjmp(ret->rlab, 1);
146         case OLIST:
147                 execute(n->left);
148                 execute(n->right);
149                 break;
150         case OIF:
151                 expr(l, &res);
152                 if(r && r->op == OELSE) {
153                         if(bool(&res))
154                                 execute(r->left);
155                         else
156                                 execute(r->right);
157                 }
158                 else if(bool(&res))
159                         execute(r);
160                 break;
161         case OWHILE:
162                 for(;;) {
163                         expr(l, &res);
164                         if(!bool(&res))
165                                 break;
166                         execute(r);
167                 }
168                 break;
169         case ODO:
170                 expr(l->left, &res);
171                 if(res.type != TINT)
172                         error("loop must have integer start");
173                 s = res.ival;
174                 expr(l->right, &res);
175                 if(res.type != TINT)
176                         error("loop must have integer end");
177                 e = res.ival;
178                 for(i = s; i <= e; i++)
179                         execute(r);
180                 break;
181         }
182 }
183
184 int
185 bool(Node *n)
186 {
187         int true = 0;
188
189         if(n->op != OCONST)
190                 fatal("bool: not const");
191
192         switch(n->type) {
193         case TINT:
194                 if(n->ival != 0)
195                         true = 1;
196                 break;
197         case TFLOAT:
198                 if(n->fval != 0.0)
199                         true = 1;
200                 break;
201         case TSTRING:
202                 if(n->string->len)
203                         true = 1;
204                 break;
205         case TLIST:
206                 if(n->l)
207                         true = 1;
208                 break;
209         }
210         return true;
211 }
212
213 void
214 convflt(Node *r, char *flt)
215 {
216         char c;
217
218         c = flt[0];
219         if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
220                 r->type = TSTRING;
221                 r->fmt = 's';
222                 r->string = strnode(flt);
223         }
224         else {
225                 r->type = TFLOAT;
226                 r->fval = atof(flt);
227         }
228 }
229
230 void
231 indir(Map *m, uvlong addr, char fmt, Node *r)
232 {
233         int i;
234         ulong lval;
235         uvlong uvval;
236         int ret;
237         uchar cval;
238         ushort sval;
239         char buf[512], reg[12];
240
241         r->op = OCONST;
242         r->fmt = fmt;
243         switch(fmt) {
244         default:
245                 error("bad pointer format '%c' for *", fmt);
246         case 'c':
247         case 'C':
248         case 'b':
249                 r->type = TINT;
250                 ret = get1(m, addr, &cval, 1);
251                 if (ret < 0)
252                         error("indir: %r");
253                 r->ival = cval;
254                 break;
255         case 'x':
256         case 'd':
257         case 'u':
258         case 'o':
259         case 'q':
260         case 'r':
261                 r->type = TINT;
262                 ret = get2(m, addr, &sval);
263                 if (ret < 0)
264                         error("indir: %r");
265                 r->ival = sval;
266                 break;
267         case 'a':
268         case 'A':
269         case 'W':
270                 r->type = TINT;
271                 ret = geta(m, addr, &uvval);
272                 if (ret < 0)
273                         error("indir: %r");
274                 r->ival = uvval;
275                 break;
276         case 'B':
277         case 'X':
278         case 'D':
279         case 'U':
280         case 'O':
281         case 'Q':
282                 r->type = TINT;
283                 ret = get4(m, addr, &lval);
284                 if (ret < 0)
285                         error("indir: %r");
286                 r->ival = lval;
287                 break;
288         case 'V':
289         case 'Y':
290         case 'Z':
291                 r->type = TINT;
292                 ret = get8(m, addr, &uvval);
293                 if (ret < 0)
294                         error("indir: %r");
295                 r->ival = uvval;
296                 break;
297         case 's':
298                 r->type = TSTRING;
299                 for(i = 0; i < sizeof(buf)-1; i++) {
300                         ret = get1(m, addr, (uchar*)&buf[i], 1);
301                         if (ret < 0)
302                                 error("indir: %r");
303                         addr++;
304                         if(buf[i] == '\0')
305                                 break;
306                 }
307                 buf[i] = 0;
308                 if(i == 0)
309                         strcpy(buf, "(null)");
310                 r->string = strnode(buf);
311                 break;
312         case 'R':
313                 r->type = TSTRING;
314                 for(i = 0; i < sizeof(buf)-2; i += 2) {
315                         ret = get1(m, addr, (uchar*)&buf[i], 2);
316                         if (ret < 0)
317                                 error("indir: %r");
318                         addr += 2;
319                         if(buf[i] == 0 && buf[i+1] == 0)
320                                 break;
321                 }
322                 buf[i++] = 0;
323                 buf[i] = 0;
324                 r->string = runenode((Rune*)buf);
325                 break;
326         case 'i':
327         case 'I':
328                 if ((*machdata->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
329                         error("indir: %r");
330                 r->type = TSTRING;
331                 r->fmt = 's';
332                 r->string = strnode(buf);
333                 break;
334         case 'f':
335                 ret = get1(m, addr, (uchar*)buf, mach->szfloat);
336                 if (ret < 0)
337                         error("indir: %r");
338                 machdata->sftos(buf, sizeof(buf), (void*) buf);
339                 convflt(r, buf);
340                 break;
341         case 'g':
342                 ret = get1(m, addr, (uchar*)buf, mach->szfloat);
343                 if (ret < 0)
344                         error("indir: %r");
345                 machdata->sftos(buf, sizeof(buf), (void*) buf);
346                 r->type = TSTRING;
347                 r->string = strnode(buf);
348                 break;
349         case 'F':
350                 ret = get1(m, addr, (uchar*)buf, mach->szdouble);
351                 if (ret < 0)
352                         error("indir: %r");
353                 machdata->dftos(buf, sizeof(buf), (void*) buf);
354                 convflt(r, buf);
355                 break;
356         case '3':       /* little endian ieee 80 with hole in bytes 8&9 */
357                 ret = get1(m, addr, (uchar*)reg, 10);
358                 if (ret < 0)
359                         error("indir: %r");
360                 memmove(reg+10, reg+8, 2);      /* open hole */
361                 memset(reg+8, 0, 2);            /* fill it */
362                 leieee80ftos(buf, sizeof(buf), reg);
363                 convflt(r, buf);
364                 break;
365         case '8':       /* big-endian ieee 80 */
366                 ret = get1(m, addr, (uchar*)reg, 10);
367                 if (ret < 0)
368                         error("indir: %r");
369                 beieee80ftos(buf, sizeof(buf), reg);
370                 convflt(r, buf);
371                 break;
372         case 'G':
373                 ret = get1(m, addr, (uchar*)buf, mach->szdouble);
374                 if (ret < 0)
375                         error("indir: %r");
376                 machdata->dftos(buf, sizeof(buf), (void*) buf);
377                 r->type = TSTRING;
378                 r->string = strnode(buf);
379                 break;
380         }
381 }
382
383 void
384 windir(Map *m, Node *addr, Node *rval, Node *r)
385 {
386         uchar cval;
387         ushort sval;
388         long lval;
389         Node res, aes;
390         int ret;
391
392         if(m == 0)
393                 error("no map for */@=");
394
395         expr(rval, &res);
396         expr(addr, &aes);
397
398         if(aes.type != TINT)
399                 error("bad type lhs of @/*");
400
401         if(m != cormap && wtflag == 0)
402                 error("not in write mode");
403
404         r->type = res.type;
405         r->fmt = res.fmt;
406         r->Store = res.Store;
407
408         switch(res.fmt) {
409         default:
410                 error("bad pointer format '%c' for */@=", res.fmt);
411         case 'c':
412         case 'C':
413         case 'b':
414                 cval = res.ival;
415                 ret = put1(m, aes.ival, &cval, 1);
416                 break;
417         case 'r':
418         case 'x':
419         case 'd':
420         case 'u':
421         case 'o':
422                 sval = res.ival;
423                 ret = put2(m, aes.ival, sval);
424                 r->ival = sval;
425                 break;
426         case 'a':
427         case 'A':
428         case 'W':
429                 ret = puta(m, aes.ival, res.ival);
430                 break;
431         case 'B':
432         case 'X':
433         case 'D':
434         case 'U':
435         case 'O':
436                 lval = res.ival;
437                 ret = put4(m, aes.ival, lval);
438                 break;
439         case 'V':
440         case 'Y':
441         case 'Z':
442                 ret = put8(m, aes.ival, res.ival);
443                 break;
444         case 's':
445         case 'R':
446                 ret = put1(m, aes.ival, (uchar*)res.string->string, res.string->len);
447                 break;
448         }
449         if (ret < 0)
450                 error("windir: %r");
451 }
452
453 void
454 call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
455 {
456         int np, i;
457         Rplace rlab;
458         Node *n, res;
459         Value *v, *f;
460         Lsym *s, *next;
461         Node *avp[Maxarg], *ava[Maxarg];
462
463         rlab.local = 0;
464
465         na = 0;
466         flatten(avp, parameters);
467         np = na;
468         na = 0;
469         flatten(ava, local);
470         if(np != na) {
471                 if(np < na)
472                         error("%s: too few arguments", fn);
473                 error("%s: too many arguments", fn);
474         }
475
476         rlab.tail = &rlab.local;
477
478         ret = &rlab;
479         for(i = 0; i < np; i++) {
480                 n = ava[i];
481                 switch(n->op) {
482                 default:
483                         error("%s: %d formal not a name", fn, i);
484                 case ONAME:
485                         expr(avp[i], &res);
486                         s = n->sym;
487                         break;
488                 case OINDM:
489                         res.cc = avp[i];
490                         res.type = TCODE;
491                         res.comt = 0;
492                         if(n->left->op != ONAME)
493                                 error("%s: %d formal not a name", fn, i);
494                         s = n->left->sym;
495                         break;
496                 }
497                 if(s->v->ret == ret)
498                         error("%s already declared at this scope", s->name);
499
500                 v = gmalloc(sizeof(Value));
501                 v->ret = ret;
502                 v->pop = s->v;
503                 s->v = v;
504                 v->scope = 0;
505                 *(rlab.tail) = s;
506                 rlab.tail = &v->scope;
507
508                 v->Store = res.Store;
509                 v->type = res.type;
510                 v->set = 1;
511         }
512
513         ret->val = retexp;
514         if(setjmp(rlab.rlab) == 0)
515                 execute(body);
516
517         for(s = rlab.local; s; s = next) {
518                 f = s->v;
519                 next = f->scope;
520                 s->v = f->pop;
521                 free(f);
522         }
523 }