source: lib/libvcl/vcc_xref.c @ b3484a

Revision b3484a, 8.8 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Catch redefinition of non-method sub's early.

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2010 Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file contains code for two cross-reference or consistency checks.
30 *
31 * The first check is simply that all subroutine, acls and backends are
32 * both defined and referenced.  Complaints about referenced but undefined
33 * or defined but unreferenced objects will be emitted.
34 *
35 * The second check recursively decends through subroutine calls to make
36 * sure that action actions are correct for the methods through which
37 * they are called.
38 */
39
40#include "config.h"
41
42#include <stdio.h>
43
44#include "vsb.h"
45
46#include "libvarnish.h"
47#include "vcc_priv.h"
48#include "vcc_compile.h"
49
50/*--------------------------------------------------------------------*/
51
52struct proccall {
53        VTAILQ_ENTRY(proccall)  list;
54        struct proc             *p;
55        struct token            *t;
56};
57
58struct procuse {
59        VTAILQ_ENTRY(procuse)   list;
60        const struct token      *t;
61        unsigned                mask;
62        const char              *use;
63};
64
65struct proc {
66        VTAILQ_HEAD(,proccall)  calls;
67        VTAILQ_HEAD(,procuse)   uses;
68        struct token            *name;
69        unsigned                ret_bitmap;
70        unsigned                exists;
71        unsigned                called;
72        unsigned                active;
73        struct token            *return_tok[VCL_RET_MAX];
74};
75
76/*--------------------------------------------------------------------
77 * Keep track of definitions and references
78 */
79
80void
81vcc_AddRef(struct vcc *tl, const struct token *t, enum symkind kind)
82{
83        struct symbol *sym;
84
85        sym = VCC_GetSymbolTok(tl, t, kind);
86        AN(sym);
87        sym->nref++;
88}
89
90int
91vcc_AddDef(struct vcc *tl, const struct token *t, enum symkind kind)
92{
93        struct symbol *sym;
94
95        sym = VCC_GetSymbolTok(tl, t, kind);
96        AN(sym);
97        sym->ndef++;
98        return (sym->ndef);
99}
100
101/*--------------------------------------------------------------------*/
102
103static void
104vcc_checkref(struct vcc *tl, const struct symbol *sym)
105{
106
107        if (sym->ndef == 0 && sym->nref != 0) {
108                vsb_printf(tl->sb, "Undefined %s %.*s, first reference:\n",
109                    VCC_SymKind(tl, sym), PF(sym->def_b));
110                vcc_ErrWhere(tl, sym->def_b);
111        } else if (sym->ndef != 0 && sym->nref == 0) {
112                vsb_printf(tl->sb, "Unused %s %.*s, defined:\n",
113                    VCC_SymKind(tl, sym), PF(sym->def_b));
114                vcc_ErrWhere(tl, sym->def_b);
115                if (!tl->err_unref) {
116                        vsb_printf(tl->sb, "(That was just a warning)\n");
117                        tl->err = 0;
118                }
119        }
120}
121
122int
123vcc_CheckReferences(struct vcc *tl)
124{
125
126        VCC_WalkSymbols(tl, vcc_checkref, SYM_NONE);
127        return (tl->err);
128}
129
130/*--------------------------------------------------------------------
131 * Returns checks
132 */
133
134static struct proc *
135vcc_findproc(struct vcc *tl, struct token *t)
136{
137        struct symbol *sym;
138        struct proc *p;
139
140
141        sym = VCC_GetSymbolTok(tl, t, SYM_SUB);
142        AN(sym);
143        if (sym->proc != NULL)
144                return (sym->proc);
145
146        p = TlAlloc(tl, sizeof *p);
147        assert(p != NULL);
148        VTAILQ_INIT(&p->calls);
149        VTAILQ_INIT(&p->uses);
150        p->name = t;
151        sym->proc = p;
152        return (p);
153}
154
155struct proc *
156vcc_AddProc(struct vcc *tl, struct token *t)
157{
158        struct proc *p;
159
160        p = vcc_findproc(tl, t);
161        p->name = t;    /* make sure the name matches the definition */
162        p->exists++;
163        return (p);
164}
165
166void
167vcc_AddUses(struct vcc *tl, const struct token *t, unsigned mask,
168    const char *use)
169{
170        struct procuse *pu;
171
172        if (tl->curproc == NULL)        /* backend */
173                return;
174        pu = TlAlloc(tl, sizeof *pu);
175        assert(pu != NULL);
176        pu->t = t;
177        pu->mask = mask;
178        pu->use = use;
179        VTAILQ_INSERT_TAIL(&tl->curproc->uses, pu, list);
180}
181
182void
183vcc_AddCall(struct vcc *tl, struct token *t)
184{
185        struct proccall *pc;
186        struct proc *p;
187
188        p = vcc_findproc(tl, t);
189        pc = TlAlloc(tl, sizeof *pc);
190        assert(pc != NULL);
191        pc->p = p;
192        pc->t = t;
193        VTAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
194}
195
196void
197vcc_ProcAction(struct proc *p, unsigned returns, struct token *t)
198{
199
200        assert(returns < VCL_RET_MAX);
201        p->ret_bitmap |= (1U << returns);
202        /* Record the first instance of this return */
203        if (p->return_tok[returns] == NULL)
204                p->return_tok[returns] = t;
205}
206
207static int
208vcc_CheckActionRecurse(struct vcc *tl, struct proc *p, unsigned bitmap)
209{
210        unsigned u;
211        struct proccall *pc;
212
213        if (!p->exists) {
214                vsb_printf(tl->sb, "Function %.*s does not exist\n",
215                    PF(p->name));
216                return (1);
217        }
218        if (p->active) {
219                vsb_printf(tl->sb, "Function recurses on\n");
220                vcc_ErrWhere(tl, p->name);
221                return (1);
222        }
223        u = p->ret_bitmap & ~bitmap;
224        if (u) {
225
226#define VCL_RET_MAC(l, U, B)                                            \
227                if (u & (1 << (VCL_RET_##U))) {                         \
228                        vsb_printf(tl->sb, "Invalid return \"" #l "\"\n");\
229                        vcc_ErrWhere(tl, p->return_tok[VCL_RET_##U]);   \
230                }
231#include "vcl_returns.h"
232#undef VCL_RET_MAC
233
234                vsb_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
235                    PF(p->name));
236                vcc_ErrWhere(tl, p->name);
237                return (1);
238        }
239        p->active = 1;
240        VTAILQ_FOREACH(pc, &p->calls, list) {
241                if (vcc_CheckActionRecurse(tl, pc->p, bitmap)) {
242                        vsb_printf(tl->sb, "\n...called from \"%.*s\"\n",
243                            PF(p->name));
244                        vcc_ErrWhere(tl, pc->t);
245                        return (1);
246                }
247        }
248        p->active = 0;
249        p->called++;
250        return (0);
251}
252
253/*--------------------------------------------------------------------*/
254
255static void
256vcc_checkaction1(struct vcc *tl, const struct symbol *sym)
257{
258        struct proc *p;
259        struct method *m;
260        int i;
261
262        p = sym->proc;
263        AN(p);
264        i = IsMethod(p->name);
265        if (i < 0)
266                return;
267        m = method_tab + i;
268        if (vcc_CheckActionRecurse(tl, p, m->ret_bitmap)) {
269                vsb_printf(tl->sb,
270                    "\n...which is the \"%s\" method\n", m->name);
271                vsb_printf(tl->sb, "Legal returns are:");
272#define VCL_RET_MAC(l, U, B)                                            \
273                if (m->ret_bitmap & ((1 << VCL_RET_##U)))       \
274                        vsb_printf(tl->sb, " \"%s\"", #l);
275
276#include "vcl_returns.h"
277#undef VCL_RET_MAC
278                vsb_printf(tl->sb, "\n");
279                tl->err = 1;
280        }
281
282}
283
284static void
285vcc_checkaction2(struct vcc *tl, const struct symbol *sym)
286{
287        struct proc *p;
288
289        p = sym->proc;
290        AN(p);
291
292        if (p->called)
293                return;
294        vsb_printf(tl->sb, "Function unused\n");
295        vcc_ErrWhere(tl, p->name);
296        if (!tl->err_unref) {
297                vsb_printf(tl->sb, "(That was just a warning)\n");
298                tl->err = 0;
299        }
300}
301
302int
303vcc_CheckAction(struct vcc *tl)
304{
305
306        VCC_WalkSymbols(tl, vcc_checkaction1, SYM_SUB);
307        if (tl->err)
308                return (tl->err);
309        VCC_WalkSymbols(tl, vcc_checkaction2, SYM_SUB);
310        return (tl->err);
311}
312
313/*--------------------------------------------------------------------*/
314
315static struct procuse *
316vcc_FindIllegalUse(const struct proc *p, const struct method *m)
317{
318        struct procuse *pu;
319
320        VTAILQ_FOREACH(pu, &p->uses, list)
321                if (!(pu->mask & m->bitval))
322                        return (pu);
323        return (NULL);
324}
325
326static int
327vcc_CheckUseRecurse(struct vcc *tl, const struct proc *p,
328    struct method *m)
329{
330        struct proccall *pc;
331        struct procuse *pu;
332
333        pu = vcc_FindIllegalUse(p, m);
334        if (pu != NULL) {
335                vsb_printf(tl->sb,
336                    "'%.*s': %s from method '%.*s'.\n",
337                    PF(pu->t), pu->use, PF(p->name));
338                vcc_ErrWhere(tl, pu->t);
339                vsb_printf(tl->sb, "\n...in subroutine \"%.*s\"\n",
340                    PF(p->name));
341                vcc_ErrWhere(tl, p->name);
342                return (1);
343        }
344        VTAILQ_FOREACH(pc, &p->calls, list) {
345                if (vcc_CheckUseRecurse(tl, pc->p, m)) {
346                        vsb_printf(tl->sb, "\n...called from \"%.*s\"\n",
347                            PF(p->name));
348                        vcc_ErrWhere(tl, pc->t);
349                        return (1);
350                }
351        }
352        return (0);
353}
354
355static void
356vcc_checkuses(struct vcc *tl, const struct symbol *sym)
357{
358        struct proc *p;
359        struct method *m;
360        struct procuse *pu;
361        int i;
362
363        p = sym->proc;
364        AN(p);
365
366        i = IsMethod(p->name);
367        if (i < 0)
368                return;
369        m = method_tab + i;
370        pu = vcc_FindIllegalUse(p, m);
371        if (pu != NULL) {
372                vsb_printf(tl->sb,
373                    "'%.*s': %s in method '%.*s'.",
374                    PF(pu->t), pu->use, PF(p->name));
375                vsb_cat(tl->sb, "\nAt: ");
376                vcc_ErrWhere(tl, pu->t);
377                return;
378        }
379        if (vcc_CheckUseRecurse(tl, p, m)) {
380                vsb_printf(tl->sb,
381                    "\n...which is the \"%s\" method\n", m->name);
382                return;
383        }
384}
385
386int
387vcc_CheckUses(struct vcc *tl)
388{
389
390        VCC_WalkSymbols(tl, vcc_checkuses, SYM_SUB);
391        return (tl->err);
392}
Note: See TracBrowser for help on using the repository browser.