This patch is NOT meant for merge.
Just a simple proof-of-concept so reviewers can quickly reproduce
the difference between placing a G_GNUC_PRINTF attribute in *.c versus
*.h file.
What it tests
-------------
* Two identical printf-style helpers (my_printf) are provided:
- v1: attribute lives in foo-v1.c
- v2: attribute lives in foo-v2.h
* Two callers (bar-v1.c, bar-v2.c) intentionally pass too few
arguments: `my_printf("%d %d %d\n", 1)`.
* A trivial Makefile builds each variant and shows whether GCC emits
the missing-argument warning.
Expected result
---------------
$ make -C poc run
// Compiling version 1 (Place G_GNUC_PRINTF in 'foo-v1.c')
No warning will appear, sliently cause security flaw
// Compiling version 2 (Place G_GNUC_PRINTF in 'foo-v2.h')
bar-v2.c:4:17: warning: more '%' conversions than data arguments [-Wformat-insufficient-args]
Signed-off-by: Sean Wei <me@sean.taipei>
---
poc/foo-v1.h | 3 +++
poc/foo-v1.c | 10 ++++++++++
poc/bar-v1.c | 6 ++++++
poc/foo-v2.h | 3 +++
poc/foo-v2.c | 10 ++++++++++
poc/bar-v2.c | 6 ++++++
poc/Makefile | 39 +++++++++++++++++++++++++++++++++++++++
7 files changed, 77 insertions(+)
create mode 100644 poc/foo-v1.h
create mode 100644 poc/foo-v1.c
create mode 100644 poc/bar-v1.c
create mode 100644 poc/foo-v2.h
create mode 100644 poc/foo-v2.c
create mode 100644 poc/bar-v2.c
create mode 100644 poc/Makefile
diff --git a/poc/foo-v1.h b/poc/foo-v1.h
new file mode 100644
index 0000000000..37b5403ba6
--- /dev/null
+++ b/poc/foo-v1.h
@@ -0,0 +1,3 @@
+#define G_GNUC_PRINTF(n, m) __attribute__((format(printf, n, m)))
+
+void my_printf(const char *fmt, ...);
diff --git a/poc/foo-v1.c b/poc/foo-v1.c
new file mode 100644
index 0000000000..ce89f95e3e
--- /dev/null
+++ b/poc/foo-v1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "foo-v2.h"
+
+void G_GNUC_PRINTF(1, 2) my_printf(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
diff --git a/poc/bar-v1.c b/poc/bar-v1.c
new file mode 100644
index 0000000000..6e707e13b4
--- /dev/null
+++ b/poc/bar-v1.c
@@ -0,0 +1,6 @@
+#include "foo-v1.h"
+
+int main() {
+ my_printf("%d %d %d\n", 1); // missing arguments
+ return 0;
+}
diff --git a/poc/foo-v2.h b/poc/foo-v2.h
new file mode 100644
index 0000000000..8bb56d3181
--- /dev/null
+++ b/poc/foo-v2.h
@@ -0,0 +1,3 @@
+#define G_GNUC_PRINTF(n, m) __attribute__((format(printf, n, m)))
+
+void G_GNUC_PRINTF(1, 2) my_printf(const char *fmt, ...);
diff --git a/poc/foo-v2.c b/poc/foo-v2.c
new file mode 100644
index 0000000000..3f18632ee6
--- /dev/null
+++ b/poc/foo-v2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "foo-v1.h"
+
+void my_printf(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
diff --git a/poc/bar-v2.c b/poc/bar-v2.c
new file mode 100644
index 0000000000..e06fd87056
--- /dev/null
+++ b/poc/bar-v2.c
@@ -0,0 +1,6 @@
+#include "foo-v2.h"
+
+int main() {
+ my_printf("%d %d %d\n", 1); // missing arguments
+ return 0;
+}
diff --git a/poc/Makefile b/poc/Makefile
new file mode 100644
index 0000000000..5725c9ff63
--- /dev/null
+++ b/poc/Makefile
@@ -0,0 +1,39 @@
+CC ?= gcc
+CFLAGS ?= -Wall
+
+TARGET = prog-v1 prog-v2
+SRCS = foo-v1.c foo-v2.c bar-v1.c bar-v2.c
+OBJS = $(SRCS:.c=.o)
+
+.PHONY: run
+
+run: clean prog-v1 prog-v2
+
+
+prog-v1:
+ @echo
+ @echo
+ @echo "### Compiling version 1 ###"
+ @echo "Place G_GNUC_PRINTF in 'foo.c' only"
+ @echo "No warning will appear, sliently cause security flaw"
+ @echo
+ $(CC) $(CFLAGS) -c foo-v1.c -o foo-v1.o
+ $(CC) $(CFLAGS) -c bar-v1.c -o bar-v1.o
+ @echo
+ $(CC) foo-v1.o bar-v1.o -o $@
+
+prog-v2:
+ @echo
+ @echo
+ @echo "### Compiling version 2###"
+ @echo "Place G_GNUC_PRINTF in 'foo.h' instead"
+ @echo "Show warning for missing arguments"
+ @echo
+ $(CC) $(CFLAGS) -c foo-v2.c -o foo-v2.o
+ $(CC) $(CFLAGS) -c bar-v2.c -o bar-v2.o
+ @echo
+ $(CC) foo-v2.o bar-v2.o -o $@
+
+clean:
+ @echo "### Clean all artifacts ###"
+ rm -f $(TARGET) $(OBJS)
--
2.49.0