summaryrefslogtreecommitdiffstats
path: root/doc/devel/variadic_debug/09-merge.cocci
diff options
context:
space:
mode:
Diffstat (limited to 'doc/devel/variadic_debug/09-merge.cocci')
-rw-r--r--doc/devel/variadic_debug/09-merge.cocci147
1 files changed, 147 insertions, 0 deletions
diff --git a/doc/devel/variadic_debug/09-merge.cocci b/doc/devel/variadic_debug/09-merge.cocci
new file mode 100644
index 0000000..4b0c1b2
--- /dev/null
+++ b/doc/devel/variadic_debug/09-merge.cocci
@@ -0,0 +1,147 @@
+// Note that this file has not actually been used in the end, since
+// 07-shortcut.cocci covers everything we needed in the project, but being
+// simpler, it makes the intent of 07-shortcut.cocci clearer
+
+
+// Splice string `s` into the format string `fmtstring` replacing the
+// %-parameter at position `pos`
+@initialize:python@
+@@
+
+#regex from https://stackoverflow.com/questions/30011379/how-can-i-parse-a-c-format-string-in-python
+import re
+fmtstring = '''\
+( # start of capture group 1
+% # literal "%"
+(?: # first option
+(?:[-+0 #]{0,5}) # optional flags
+(?:\d+|\*)? # width
+(?:\.(?:\d+|\*))? # precision
+(?:h|l|ll|w|I|I32|I64)? # size
+[cCdiouxXeEfgGaAnpsSZ] # type
+) | # OR
+%%) # literal "%%"
+'''
+
+regex = re.compile(fmtstring, re.X)
+
+def parse_format(f):
+ return tuple((m.span(), m.group()) for m in
+ regex.finditer(f))
+
+def insert_at_pos(fmt, s, pos):
+ formats = parse_format(fmt)
+ span, format = formats[pos]
+ acc = fmt[:span[0]]
+ if s.startswith('"'):
+ acc += s[1:]
+ else:
+ acc += '" '
+ acc += s
+ if acc.endswith('"'):
+ acc = acc[:-1] + fmt[span[1]:]
+ else:
+ acc += ' "'
+ acc += fmt[span[1]:]
+ return acc
+
+// Identify the redundant snprintfs (within a locked region)
+@a exists@
+expression lock, E, L;
+expression list args_before, args, args_after;
+identifier buf;
+expression format1, format2;
+type T;
+position p1, p2;
+@@
+
+{
+...
+T buf;
+...
+ldap_pvt_thread_mutex_lock(lock);
+...
+snprintf@p1( buf, E, format1, args );
+...
+ldap_pvt_thread_mutex_unlock(lock);
+...
+Debug@p2( L, format2, args_before, buf, args_after );
+...
+}
+
+// Merge the format strings with insert_at_pos above
+@script:python a_process@
+format1 << a.format1;
+format2 << a.format2;
+args_before << a.args_before;
+merged;
+@@
+
+pos = len(args_before.elements)
+coccinelle.merged = insert_at_pos(format2, format1, pos)
+
+// And merge the two together, replacing the extra buffer that's not used anymore
+@a_replace@
+position a.p1, a.p2;
+identifier a_process.merged;
+
+expression lock, E, L;
+expression list args_before, args, args_after;
+identifier buf;
+expression format1, format2;
+type T;
+@@
+
+{
+...
+-T buf;
+...
+ldap_pvt_thread_mutex_lock(lock);
+...
+-snprintf@p1( buf, E, format1, args );
++Debug( L, merged, args_before, args, args_after );
+...
+ldap_pvt_thread_mutex_unlock(lock);
+...
+-Debug@p2( L, format2, args_before, buf, args_after );
+...
+}
+
+// Once again (same as the 'a' series above, but those that remain to be sorted
+// now don't need to stay within a locked region
+@b exists@
+expression E, L;
+expression list args_before, args, args_after;
+identifier buf;
+expression format1, format2;
+position p1, p2;
+@@
+
+snprintf@p1( buf, E, format1, args );
+...
+Debug@p2( L, format2, args_before, buf, args_after );
+
+@script:python b_process@
+format1 << b.format1;
+format2 << b.format2;
+args_before << b.args_before;
+merged;
+@@
+
+pos = len(args_before.elements)
+coccinelle.merged = insert_at_pos(format2, format1, pos)
+
+@b_replace@
+position b.p1, b.p2;
+identifier b_process.merged;
+
+expression E, L;
+expression list args_before, args, args_after;
+identifier buf;
+expression format1, format2;
+@@
+
+-snprintf@p1( buf, E, format1, args );
++Debug( L, merged, args_before, args, args_after );
+...
+-Debug@p2( L, format2, args_before, buf, args_after );