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