File Coverage

hax/forbid_outofblock_ops.c.inc
Criterion Covered Total %
statement 22 43 51.1
branch 8 28 28.5
condition n/a
subroutine n/a
pod n/a
total 30 71 42.2


line stmt bran cond sub pod time code
1             /* vi: set ft=c : */
2              
3             #if !HAVE_PERL_VERSION(5, 16, 0)
4             # define CopLABEL_len_flags(c,len,flags) Perl_fetch_cop_label(aTHX_ (c), len, flags)
5             #endif
6              
7             enum {
8             FORBID_LOOPEX_DEFAULT = (1<<0),
9             };
10              
11 80           static void walk_ops_forbid(pTHX_ OP *o, U32 flags, HV *permittedloops, const char *blockname)
12             {
13 80           bool is_loop = FALSE;
14 80           SV *labelsv = NULL;
15              
16 80           switch(o->op_type) {
17             case OP_NEXTSTATE:
18 12           PL_curcop = (COP *)o;
19 12           return;
20              
21             case OP_RETURN:
22             goto forbid;
23              
24             case OP_GOTO:
25             /* TODO: This might be safe, depending on the target */
26             goto forbid;
27              
28             case OP_NEXT:
29             case OP_LAST:
30             case OP_REDO:
31             {
32             /* OPf_SPECIAL means this is a default loopex */
33 0 0         if(o->op_flags & OPf_SPECIAL) {
34 0 0         if(flags & FORBID_LOOPEX_DEFAULT)
35             goto forbid;
36              
37             break;
38             }
39             /* OPf_STACKED means it's a dynamically computed label */
40 0 0         if(o->op_flags & OPf_STACKED)
41             goto forbid;
42              
43 0           SV *target = newSVpv(cPVOPo->op_pv, strlen(cPVOPo->op_pv));
44             #if HAVE_PERL_VERSION(5, 16, 0)
45 0 0         if(cPVOPo->op_private & OPpPV_IS_UTF8)
46 0           SvUTF8_on(target);
47             #endif
48 0           SAVEFREESV(target);
49              
50 0 0         if(hv_fetch_ent(permittedloops, target, FALSE, 0))
51             break;
52              
53             goto forbid;
54             }
55              
56             case OP_LEAVELOOP:
57             {
58             STRLEN label_len;
59             U32 label_flags;
60 0           const char *label_pv = CopLABEL_len_flags(PL_curcop, &label_len, &label_flags);
61              
62 0 0         if(label_pv) {
63 0           labelsv = newSVpvn(label_pv, label_len);
64 0 0         if(label_flags & SVf_UTF8)
65 0           SvUTF8_on(labelsv);
66 0           SAVEFREESV(labelsv);
67              
68 0           sv_inc(HeVAL(hv_fetch_ent(permittedloops, labelsv, TRUE, 0)));
69             }
70              
71 0           is_loop = TRUE;
72             break;
73             }
74              
75             forbid:
76 0           croak("Can't \"%s\" out of %s", PL_op_name[o->op_type], blockname);
77              
78             default:
79             break;
80             }
81              
82 68 100         if(!(o->op_flags & OPf_KIDS))
83             return;
84              
85 28           OP *kid = cUNOPo->op_first;
86 96 100         while(kid) {
87 68           walk_ops_forbid(aTHX_ kid, flags, permittedloops, blockname);
88 68 100         kid = OpSIBLING(kid);
89              
90 68 50         if(is_loop) {
91             /* Now in the body of the loop; we can permit loopex default */
92 68           flags &= ~FORBID_LOOPEX_DEFAULT;
93             }
94             }
95              
96 28 50         if(is_loop && labelsv) {
97 0           HE *he = hv_fetch_ent(permittedloops, labelsv, FALSE, 0);
98 0 0         if(SvIV(HeVAL(he)) > 1)
    0          
99 0           sv_dec(HeVAL(he));
100             else
101 0           hv_delete_ent(permittedloops, labelsv, 0, 0);
102             }
103             }
104              
105             #ifndef forbid_outofblock_ops
106             # define forbid_outofblock_ops(o, blockname) S_forbid_outofblock_ops(aTHX_ o, blockname)
107 12           static void S_forbid_outofblock_ops(pTHX_ OP *o, const char *blockname)
108             {
109 12           ENTER;
110 12           SAVEVPTR(PL_curcop);
111              
112 12           HV *looplabels = newHV();
113 12           SAVEFREESV((SV *)looplabels);
114              
115 12           walk_ops_forbid(aTHX_ o, FORBID_LOOPEX_DEFAULT, looplabels, blockname);
116              
117 12           LEAVE;
118 12           }
119             #endif