xref: /netbsd-src/external/bsd/openldap/dist/doc/devel/variadic_debug/07-shortcut.cocci (revision e670fd5c413e99c2f6a37901bb21c537fcd322d2)
1// Splice string `s` into the format string `fmtstring` replacing the
2// %-parameter at position `pos`
3@initialize:python@
4@@
5
6# regex from https://stackoverflow.com/questions/30011379/how-can-i-parse-a-c-format-string-in-python
7import re
8fmtstring = '''\
9(                                  # start of capture group 1
10%                                  # literal "%"
11(?:                                # first option
12(?:[-+0 #]{0,5})                   # optional flags
13(?:\d+|\*)?                        # width
14(?:\.(?:\d+|\*))?                  # precision
15(?:h|l|ll|w|I|I32|I64)?            # size
16[cCdiouxXeEfgGaAnpsSZ]             # type
17) |                                # OR
18%%)                                # literal "%%"
19'''
20
21regex = re.compile(fmtstring, re.X)
22
23def parse_format(f):
24    return tuple((m.span(), m.group()) for m in
25        regex.finditer(f))
26
27def insert_at_pos(fmt, s, pos):
28    formats = parse_format(fmt)
29    span, format = formats[pos]
30    acc = fmt[:span[0]]
31    if s.startswith('"'):
32        acc += s[1:]
33    else:
34        acc += '" '
35        acc += s
36    if acc.endswith('"'):
37        acc = acc[:-1] + fmt[span[1]:]
38    else:
39        acc += ' "'
40        acc += fmt[span[1]:]
41    return acc
42
43// rest of the file implements the same as 09-merge.cocci
44// The main difference is that we only match on snprintf and Debug that are
45// directly adjacent, not based on control flow information which trips
46// coccinelle's model-checker
47@shortcut@
48identifier buf;
49expression E, L;
50expression list args_before, args, args_after;
51expression format1, format2;
52position p1, p2;
53@@
54
55snprintf@p1( buf, E, format1, args );
56Debug@p2( L, format2, args_before, buf, args_after );
57
58// use insert_at_pos above to construct the new format-string
59@script:python shortcut_process@
60format1 << shortcut.format1;
61format2 << shortcut.format2;
62args_before << shortcut.args_before;
63merged;
64@@
65
66pos = len(args_before.elements)
67coccinelle.merged = insert_at_pos(format2, format1, pos)
68
69@shortcut_replace@
70position shortcut.p1, shortcut.p2;
71identifier shortcut_process.merged;
72
73identifier buf;
74expression E, L;
75expression list args_before, args, args_after;
76expression format1, format2;
77@@
78
79-snprintf@p1( buf, E, format1, args );
80-Debug@p2( L, format2, args_before, buf, args_after );
81+Debug( L, merged, args_before, args, args_after );
82
83@shortcut_locked@
84identifier buf;
85expression E, L, lock;
86expression list args_before, args, args_after;
87expression format1, format2;
88position p1, p2;
89@@
90
91ldap_pvt_thread_mutex_lock(lock);
92snprintf@p1( buf, E, format1, args );
93ldap_pvt_thread_mutex_unlock(lock);
94Debug@p2( L, format2, args_before, buf, args_after );
95
96// use insert_at_pos above to construct the new format-string
97@script:python shortcut_locked_process@
98format1 << shortcut_locked.format1;
99format2 << shortcut_locked.format2;
100args_before << shortcut_locked.args_before;
101merged;
102@@
103
104pos = len(args_before.elements)
105coccinelle.merged = insert_at_pos(format2, format1, pos)
106
107@shortcut_locked_replace@
108position shortcut_locked.p1, shortcut_locked.p2;
109identifier shortcut_locked_process.merged;
110
111identifier buf;
112expression E, L, lock;
113expression list args_before, args, args_after;
114expression format1, format2;
115@@
116
117ldap_pvt_thread_mutex_lock(lock);
118-snprintf@p1( buf, E, format1, args );
119+Debug( L, merged, args_before, args, args_after );
120ldap_pvt_thread_mutex_unlock(lock);
121-Debug@p2( L, format2, args_before, buf, args_after );
122
123// so long as we don't reference 'buf' afterwards, no need to keep it defined.
124// A lot of pattern-matching is spelled out explicitly to work around the fact
125// that the state space doesn't get compressed otherwise.
126@@
127type T;
128identifier buf, id;
129expression E, lock;
130initializer I;
131@@
132{
133-\( T buf = I; \| T buf; \)
134(
135 ldap_pvt_thread_mutex_lock(lock);
136|
137)
138(
139 Debug( ... );
140&
141 ... when != buf
142)
143(
144 ldap_pvt_thread_mutex_unlock(lock);
145|
146)
147(
148|
149 continue;
150|
151 break;
152|
153 goto id;
154|
155 \(
156  return E;
157 \&
158  ... when != buf
159 \)
160)
161}
162
163// the rest identifies and removes a (newly-)redundant LogTest check
164@if_guard@
165position p;
166statement s;
167@@
168
169(
170 if ( ... ) {@p
171  Debug( ... );
172 } else s
173|
174 if ( ... ) {@p
175  Debug( ... );
176 }
177)
178
179@else_guard@
180position p;
181statement s;
182@@
183
184if ( ... ) s
185else {@p
186 Debug( ... );
187}
188
189@loop_guard@
190position p;
191@@
192
193(
194 while ( ... ) {@p
195  Debug( ... );
196 }
197|
198 for ( ...;...;... ) {@p
199  Debug( ... );
200 }
201)
202
203@@
204position p != { if_guard.p , else_guard.p, loop_guard.p };
205@@
206-{@p
207 Debug( ... );
208-}
209
210@useless_if@
211expression L;
212@@
213
214-if ( LogTest( L ) ) {
215 Debug( L, ... );
216-}
217