varnish-cache/lib/libvcc/vcc_xref.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9 24
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15 24
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 24
 * SUCH DAMAGE.
29
 *
30
 * This file contains code for two cross-reference or consistency checks.
31
 *
32
 * The first check is simply that all subroutine, acls and backends are
33 14040
 * both defined and referenced.  Complaints about referenced but undefined
34 14040
 * or defined but unreferenced objects will be emitted.
35
 *
36
 * The second check recursively decends through subroutine calls to make
37
 * sure that action actions are correct for the methods through which
38
 * they are called.
39
 */
40
41
#include "config.h"
42
43
#include <string.h>
44 24
#include "vcc_compile.h"
45
46
/*--------------------------------------------------------------------*/
47
48
struct proccall {
49
        VTAILQ_ENTRY(proccall)  list;
50 24
        struct symbol           *sym;
51
        struct token            *t;
52
        struct proc             *fm;
53
};
54 24
55
struct procuse {
56
        VTAILQ_ENTRY(procuse)   list;
57
        const struct token      *t1;
58 24
        const struct token      *t2;
59
        const struct symbol     *sym;
60
        const struct xrefuse    *use;
61
        unsigned                mask;
62
        struct proc             *fm;
63 24
};
64
65
struct procpriv {
66
        VTAILQ_ENTRY(procpriv)  list;
67
        const char              *vmod;
68
};
69
70 24
/*--------------------------------------------------------------------*/
71
72
static void
73 6346944
vcc_checkref(struct vcc *tl, const struct symbol *sym)
74
{
75 24
76 6346944
        if (sym->noref)
77 5662068
                return;
78 684876
        if (sym->ndef == 0 && sym->nref != 0) {
79 60
                AN(sym->ref_b);
80 72
                VSB_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
81 36
                    sym->kind->name, PF(sym->ref_b));
82 36
                vcc_ErrWhere(tl, sym->ref_b);
83 684876
        } else if (sym->ndef != 0 && sym->nref == 0) {
84 1524
                AN(sym->def_b);
85 3048
                VSB_printf(tl->sb, "Unused %s %.*s, defined:\n",
86 1524
                    sym->kind->name, PF(sym->def_b));
87 1524
                vcc_ErrWhere(tl, sym->def_b);
88 1524
                if (!tl->err_unref)
89 1476
                        vcc_Warn(tl);
90 1524
        }
91 6346944
}
92
93
int
94 32244
vcc_CheckReferences(struct vcc *tl)
95
{
96
97 32220
        VCC_WalkSymbols(tl, vcc_checkref, SYM_MAIN, SYM_NONE);
98 32220
        return (tl->err);
99
}
100
101
/*--------------------------------------------------------------------
102
 * Returns checks
103
 */
104 24
105
const struct xrefuse XREF_READ[1] = {{"xref_read", "Not available"}};
106
const struct xrefuse XREF_WRITE[1] = {{"xref_write", "Cannot be set"}};
107
const struct xrefuse XREF_UNSET[1] = {{"xref_unset", "Cannot be unset"}};
108
const struct xrefuse XREF_ACTION[1] = {{"xref_action", "Not a valid action"}};
109
110
void
111 1864464
vcc_AddUses(struct vcc *tl, const struct token *t1, const struct token *t2,
112
    const struct symbol *sym, const struct xrefuse *use)
113
{
114
        struct procuse *pu;
115
116 1864464
        AN(tl->curproc);
117 1864464
        pu = TlAlloc(tl, sizeof *pu);
118 1864464
        AN(pu);
119 1864464
        AN(sym);
120 1864464
        AN(use);
121 1864464
        AN(use->name);
122 1864464
        pu->t1 = t1;
123 1864464
        pu->t2 = t2;
124 1864464
        if (pu->t2 == NULL) {
125 1509780
                pu->t2 = vcc_PeekTokenFrom(tl, t1);
126 1509780
                AN(pu->t2);
127 1509780
        }
128 1864464
        pu->sym = sym;
129 1864464
        pu->use = use;
130 1864464
        pu->fm = tl->curproc;
131
132 1864464
        if (pu->use == XREF_READ)
133 1410432
                pu->mask = sym->r_methods;
134 454032
        else if (pu->use == XREF_WRITE)
135 321900
                pu->mask = sym->w_methods;
136 132132
        else if (pu->use == XREF_UNSET)
137 32784
                pu->mask = sym->u_methods;
138 99348
        else if (pu->use == XREF_ACTION)
139 99348
                pu->mask = sym->action_mask;
140
        else
141 0
                WRONG("wrong xref use");
142
143 1864464
        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
144 1864464
}
145
146
void
147 774900
vcc_AddCall(struct vcc *tl, struct token *t, struct symbol *sym)
148
{
149
        struct proccall *pc;
150
151 774900
        AN(sym);
152 774900
        pc = TlAlloc(tl, sizeof *pc);
153 774900
        AN(pc);
154 774900
        pc->sym = sym;
155 774900
        pc->t = t;
156 774900
        pc->fm = tl->curproc;
157 774900
        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
158 774900
}
159
160
void
161 715644
vcc_ProcAction(struct proc *p, unsigned returns, unsigned mask, struct token *t)
162
{
163
164 715644
        assert(returns < VCL_RET_MAX);
165 715644
        p->ret_bitmap |= (1U << returns);
166 715644
        p->okmask &= mask;
167
        /* Record the first instance of this return */
168 715644
        if (p->return_tok[returns] == NULL)
169 713700
                p->return_tok[returns] = t;
170 715644
}
171
172
static int
173 2409192
vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
174
{
175
        unsigned u;
176
        struct proccall *pc;
177
178 2409192
        AN(p);
179 2409192
        if (p->active) {
180 24
                VSB_cat(tl->sb, "Subroutine recurses on\n");
181 24
                vcc_ErrWhere(tl, p->name);
182 24
                return (1);
183
        }
184 2409168
        u = p->ret_bitmap & ~bitmap;
185 2409168
        if (u) {
186
187
#define VCL_RET_MAC(l, U, B)                                            \
188
                if (u & (1 << (VCL_RET_##U))) {                         \
189
                        VSB_printf(tl->sb, "Invalid return \"" #l "\"\n");\
190
                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
191
                }
192
#include "tbl/vcl_returns.h"
193
194 24
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
195 12
                    PF(p->name));
196 12
                vcc_ErrWhere(tl, p->name);
197 12
                return (1);
198
        }
199
200
        // more references than calls -> sub is referenced for dynamic calls
201 2409156
        u = (p->sym->nref > p->called);
202
203 2409156
        p->active = 1;
204 3694464
        VTAILQ_FOREACH(pc, &p->calls, list) {
205 1285356
                if (pc->sym->proc == NULL) {
206 0
                        VSB_printf(tl->sb, "Subroutine %s does not exist\n",
207 0
                            pc->sym->name);
208 0
                        vcc_ErrWhere(tl, pc->t);
209 0
                        return (1);
210
                }
211 1285356
                pc->sym->proc->calledfrom |= p->calledfrom;
212 1285356
                pc->sym->proc->called++;
213 1285356
                pc->sym->nref += u;
214 1285356
                if (vcc_CheckActionRecurse(tl, pc->sym->proc, bitmap)) {
215 96
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
216 48
                            PF(p->name));
217 48
                        vcc_ErrWhere(tl, pc->t);
218 48
                        return (1);
219
                }
220 1285308
                p->okmask &= pc->sym->proc->okmask;
221 1285308
        }
222 2409108
        p->active = 0;
223 2409108
        return (0);
224 2409192
}
225
226
/*--------------------------------------------------------------------*/
227
228
static void
229 1123836
vcc_checkaction(struct vcc *tl, const struct symbol *sym)
230
{
231
        struct proc *p;
232
        unsigned bitmap;
233
234 1123836
        p = sym->proc;
235 1123836
        AN(p);
236 1123836
        AN(p->name);
237
238 1123836
        if (p->method == NULL) {
239 674616
                bitmap = ~0U;
240 674616
        } else {
241 449220
                bitmap = p->method->ret_bitmap;
242 449220
                p->calledfrom = p->method->bitval;
243
        }
244
245 1123836
        if (! vcc_CheckActionRecurse(tl, p, bitmap))
246 1123800
                return;
247
248 36
        tl->err = 1;
249 36
        if (p->method == NULL)
250 24
                return;
251
252 24
        VSB_printf(tl->sb,
253 12
                   "\n...which is the \"%s\" subroutine\n", p->method->name);
254 12
        VSB_cat(tl->sb, "Legal returns are:");
255
#define VCL_RET_MAC(l, U, B)                                            \
256
        if (p->method->ret_bitmap & ((1 << VCL_RET_##U)))               \
257
                VSB_printf(tl->sb, " \"%s\"", #l);
258
259
#include "tbl/vcl_returns.h"
260 12
        VSB_cat(tl->sb, "\n");
261 1123836
}
262
263
int
264 32112
vcc_CheckAction(struct vcc *tl)
265
{
266
267 32112
        VCC_WalkSymbols(tl, vcc_checkaction, SYM_MAIN, SYM_SUB);
268 32112
        return (tl->err);
269
}
270
271
/*--------------------------------------------------------------------*/
272
273
static struct procuse *
274 2121816
vcc_illegal_write(struct vcc *tl, struct procuse *pu, const struct method *m)
275
{
276
277 2121816
        if (pu->mask || pu->use != XREF_WRITE)
278 2121660
                return (NULL);
279
280 156
        if (pu->sym->r_methods == 0) {
281 12
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
282 12
                VSB_cat(tl->sb, "Variable cannot be set.\n");
283 12
                return (NULL);
284
        }
285
286 144
        if (!(pu->sym->r_methods & m->bitval)) {
287 24
                pu->use = XREF_READ; /* NB: change the error message. */
288 24
                return (pu);
289
        }
290
291 120
        vcc_ErrWhere2(tl, pu->t1, pu->t2);
292 120
        VSB_cat(tl->sb, "Variable is read only.\n");
293 120
        return (NULL);
294 2121816
}
295
296
static struct procuse *
297 3511884
vcc_FindIllegalUse(struct vcc *tl, struct proc *p, const struct method *m)
298
{
299 3511884
        struct procuse *pu, *pw, *r = NULL;
300
301 10454172
        VTAILQ_FOREACH(pu, &p->uses, list) {
302 6942288
                p->okmask &= pu->mask;
303 6942288
                if (m == NULL)
304 4820472
                        continue;
305 2121816
                pw = vcc_illegal_write(tl, pu, m);
306 2121816
                if (r != NULL)
307 84
                        continue;
308 2121732
                if (tl->err)
309 132
                        r = pw;
310 2121600
                else if (!(pu->mask & m->bitval))
311 348
                        r = pu;
312 2121732
        }
313 3511884
        return (r);
314
}
315
316
static int
317 2394684
vcc_CheckUseRecurse(struct vcc *tl, struct proc *p,
318
    const struct method *m)
319
{
320
        struct proccall *pc;
321
        struct procuse *pu;
322
323 2394684
        pu = vcc_FindIllegalUse(tl, p, m);
324 2394684
        if (pu != NULL) {
325 36
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
326 72
                VSB_printf(tl->sb, "%s from subroutine '%s'.\n",
327 36
                    pu->use->err, m->name);
328 72
                VSB_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
329 36
                    PF(pu->fm->name));
330 36
                vcc_ErrWhere(tl, p->name);
331 36
                return (1);
332
        }
333 2394648
        if (tl->err)
334 12
                return (1);
335 3672492
        VTAILQ_FOREACH(pc, &p->calls, list) {
336 1277916
                if (vcc_CheckUseRecurse(tl, pc->sym->proc, m)) {
337 120
                        VSB_printf(tl->sb, "\n...called from \"%.*s\"\n",
338 60
                            PF(p->name));
339 60
                        vcc_ErrWhere(tl, pc->t);
340 60
                        return (1);
341
                }
342 1277856
                p->okmask &= pc->sym->proc->okmask;
343 1277856
        }
344 2394576
        return (0);
345 2394684
}
346
347
static void
348 1117200
vcc_checkuses(struct vcc *tl, const struct symbol *sym)
349
{
350
        struct proc *p;
351
        struct procuse *pu;
352
353 1117200
        p = sym->proc;
354 1117200
        AN(p);
355 1117200
        pu = vcc_FindIllegalUse(tl, p, p->method);
356 1117200
        if (pu != NULL) {
357 312
                vcc_ErrWhere2(tl, pu->t1, pu->t2);
358 624
                VSB_printf(tl->sb, "%s in subroutine '%.*s'.",
359 312
                    pu->use->err, PF(p->name));
360 312
                VSB_cat(tl->sb, "\nAt: ");
361 312
                return;
362
        }
363 1116888
        ERRCHK(tl);
364 1116768
        if (vcc_CheckUseRecurse(tl, p, p->method)) {
365 96
                VSB_printf(tl->sb,
366 48
                    "\n...which is the \"%s\" subroutine\n", p->method->name);
367 48
                return;
368
        }
369 1117200
}
370
371
/*
372
 * Used from a second symbol walk because vcc_checkuses is more precise for
373
 * subroutines called from methods. We catch here subs used for dynamic calls
374
 * and with vcc_err_unref = off
375
 */
376
static void
377 1105740
vcc_checkpossible(struct vcc *tl, const struct symbol *sym)
378
{
379
        struct proc *p;
380
381 1105740
        p = sym->proc;
382 1105740
        AN(p);
383
384 1105740
        if (p->okmask != 0)
385 1105716
                return;
386
387 24
        VSB_cat(tl->sb, "Impossible Subroutine");
388 24
        vcc_ErrWhere(tl, p->name);
389 1105740
}
390
391
int
392 32076
vcc_CheckUses(struct vcc *tl)
393
{
394
395 32076
        VCC_WalkSymbols(tl, vcc_checkuses, SYM_MAIN, SYM_SUB);
396 32076
        if (tl->err)
397 480
                return (tl->err);
398 31596
        VCC_WalkSymbols(tl, vcc_checkpossible, SYM_MAIN, SYM_SUB);
399 31596
        return (tl->err);
400 32076
}
401
402
/*---------------------------------------------------------------------*/
403
404
static void v_matchproto_(symwalk_f)
405 2328
vcc_instance_info(struct vcc *tl, const struct symbol *sym)
406
{
407
408 2328
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
409 2328
        AN(sym->rname);
410 2328
        Fc(tl, 0, "\t{ .p = (uintptr_t *)&%s, .name = \"", sym->rname);
411 2328
        VCC_SymName(tl->fc, sym);
412 2328
        Fc(tl, 0, "\" },\n");
413 2328
}
414
415
void
416 14040
VCC_InstanceInfo(struct vcc *tl)
417
{
418 14040
        Fc(tl, 0, "\nstatic const struct vpi_ii VGC_instance_info[] = {\n");
419 14040
        VCC_WalkSymbols(tl, vcc_instance_info, SYM_MAIN, SYM_INSTANCE);
420 14040
        Fc(tl, 0, "\t{ .p = NULL, .name = \"\" }\n");
421 14040
        Fc(tl, 0, "};\n");
422 14040
}
423
424
/*---------------------------------------------------------------------*/
425
426
static int sym_type_len;
427
428
static void v_matchproto_(symwalk_f)
429 3056964
vcc_xreftable_len(struct vcc *tl, const struct symbol *sym)
430
{
431
        int len;
432
433 3056964
        (void)tl;
434 3056964
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
435 3056964
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
436 3056964
        len = strlen(sym->type->name);
437 3056964
        if (sym_type_len < len)
438 87648
                sym_type_len = len;
439 3056964
}
440
441
static void v_matchproto_(symwalk_f)
442 3056964
vcc_xreftable(struct vcc *tl, const struct symbol *sym)
443
{
444
445 3056964
        CHECK_OBJ_NOTNULL(sym, SYMBOL_MAGIC);
446 3056964
        CHECK_OBJ_NOTNULL(sym->kind, KIND_MAGIC);
447 3056964
        CHECK_OBJ_NOTNULL(sym->type, TYPE_MAGIC);
448 3056964
        Fc(tl, 0, " * %-8s ", sym->kind->name);
449 3056964
        Fc(tl, 0, " %-*s ", sym_type_len, sym->type->name);
450 3056964
        Fc(tl, 0, " %2u %2u ", sym->lorev, sym->hirev);
451 3056964
        VCC_SymName(tl->fc, sym);
452 3056964
        if (sym->wildcard != NULL)
453 84240
                Fc(tl, 0, "*");
454 3056964
        Fc(tl, 0, "\n");
455 3056964
}
456
457
void
458 14040
VCC_XrefTable(struct vcc *tl)
459
{
460
461
#define VCC_NAMESPACE(U, l)                                             \
462
        Fc(tl, 0, "\n/*\n * Symbol Table " #U "\n *\n");                \
463
        sym_type_len = 0;                                               \
464
        VCC_WalkSymbols(tl, vcc_xreftable_len, SYM_##U, SYM_NONE);      \
465
        VCC_WalkSymbols(tl, vcc_xreftable, SYM_##U, SYM_NONE);          \
466
        Fc(tl, 0, "*/\n\n");
467
#include "vcc_namespace.h"
468 14040
}
469
470
/*---------------------------------------------------------------------
471
 * mark vmod as referenced, return NULL if not yet marked, vmod if marked
472
 */
473
474
const char *
475 1620
vcc_MarkPriv(struct vcc *tl, struct procprivhead *head,
476
    const char *vmod)
477
{
478
        struct procpriv *pp;
479
480 1620
        AN(vmod);
481
482 1620
        VTAILQ_FOREACH(pp, head, list) {
483 1104
                if (pp->vmod == vmod)
484 1104
                        return (vmod);
485 0
                AN(strcmp(pp->vmod, vmod));
486 0
        }
487
488 516
        pp = TlAlloc(tl, sizeof *pp);
489 516
        assert(pp != NULL);
490 516
        pp->vmod = vmod;
491 516
        VTAILQ_INSERT_TAIL(head, pp, list);
492 516
        return (NULL);
493 1620
}