1// Note that this file has not actually been used in the end, since 2// 07-shortcut.cocci covers everything we needed in the project, but being 3// simpler, it makes the intent of 07-shortcut.cocci clearer 4 5 6// Splice string `s` into the format string `fmtstring` replacing the 7// %-parameter at position `pos` 8@initialize:python@ 9@@ 10 11#regex from https://stackoverflow.com/questions/30011379/how-can-i-parse-a-c-format-string-in-python 12import re 13fmtstring = '''\ 14( # start of capture group 1 15% # literal "%" 16(?: # first option 17(?:[-+0 #]{0,5}) # optional flags 18(?:\d+|\*)? # width 19(?:\.(?:\d+|\*))? # precision 20(?:h|l|ll|w|I|I32|I64)? # size 21[cCdiouxXeEfgGaAnpsSZ] # type 22) | # OR 23%%) # literal "%%" 24''' 25 26regex = re.compile(fmtstring, re.X) 27 28def parse_format(f): 29 return tuple((m.span(), m.group()) for m in 30 regex.finditer(f)) 31 32def insert_at_pos(fmt, s, pos): 33 formats = parse_format(fmt) 34 span, format = formats[pos] 35 acc = fmt[:span[0]] 36 if s.startswith('"'): 37 acc += s[1:] 38 else: 39 acc += '" ' 40 acc += s 41 if acc.endswith('"'): 42 acc = acc[:-1] + fmt[span[1]:] 43 else: 44 acc += ' "' 45 acc += fmt[span[1]:] 46 return acc 47 48// Identify the redundant snprintfs (within a locked region) 49@a exists@ 50expression lock, E, L; 51expression list args_before, args, args_after; 52identifier buf; 53expression format1, format2; 54type T; 55position p1, p2; 56@@ 57 58{ 59... 60T buf; 61... 62ldap_pvt_thread_mutex_lock(lock); 63... 64snprintf@p1( buf, E, format1, args ); 65... 66ldap_pvt_thread_mutex_unlock(lock); 67... 68Debug@p2( L, format2, args_before, buf, args_after ); 69... 70} 71 72// Merge the format strings with insert_at_pos above 73@script:python a_process@ 74format1 << a.format1; 75format2 << a.format2; 76args_before << a.args_before; 77merged; 78@@ 79 80pos = len(args_before.elements) 81coccinelle.merged = insert_at_pos(format2, format1, pos) 82 83// And merge the two together, replacing the extra buffer that's not used anymore 84@a_replace@ 85position a.p1, a.p2; 86identifier a_process.merged; 87 88expression lock, E, L; 89expression list args_before, args, args_after; 90identifier buf; 91expression format1, format2; 92type T; 93@@ 94 95{ 96... 97-T buf; 98... 99ldap_pvt_thread_mutex_lock(lock); 100... 101-snprintf@p1( buf, E, format1, args ); 102+Debug( L, merged, args_before, args, args_after ); 103... 104ldap_pvt_thread_mutex_unlock(lock); 105... 106-Debug@p2( L, format2, args_before, buf, args_after ); 107... 108} 109 110// Once again (same as the 'a' series above, but those that remain to be sorted 111// now don't need to stay within a locked region 112@b exists@ 113expression E, L; 114expression list args_before, args, args_after; 115identifier buf; 116expression format1, format2; 117position p1, p2; 118@@ 119 120snprintf@p1( buf, E, format1, args ); 121... 122Debug@p2( L, format2, args_before, buf, args_after ); 123 124@script:python b_process@ 125format1 << b.format1; 126format2 << b.format2; 127args_before << b.args_before; 128merged; 129@@ 130 131pos = len(args_before.elements) 132coccinelle.merged = insert_at_pos(format2, format1, pos) 133 134@b_replace@ 135position b.p1, b.p2; 136identifier b_process.merged; 137 138expression E, L; 139expression list args_before, args, args_after; 140identifier buf; 141expression format1, format2; 142@@ 143 144-snprintf@p1( buf, E, format1, args ); 145+Debug( L, merged, args_before, args, args_after ); 146... 147-Debug@p2( L, format2, args_before, buf, args_after ); 148