threads / patch / 61607

patch, 4 partsvarargs functions with __attributes__(())

Subject: [PATCH 0/4] varargs functions with __attributes__(())

## tl;dr

9 messages between Jun 8, 2024 and Jun 11, 2024. Diffs are folded; open one to read it.

replies: 8people: 3as markdown or json

Junio C Hamano· Jun 8, 2024, 18:37 UTC · lore

There are several varargs functions that take either NULL-terminated list of parameters, or printf-like format followed by list of parameters, that are not declared as such with __attributes__(()).

Adding such a missing attribute to trace2_region_enter_printf() revealed that an existing call to it was trying to format a value of type size_t using "%d", which is not such an excellent idea. Other functions that were lacking attributes fortunately did not have any broken existing callers.

Junio C Hamano (4):
  __attribute__: trace2_region_enter_printf() is like "printf"
  __attribute__: remove redundant __attribute__ declaration for
    git_die_config()
  __attribute__: mark some functions with LAST_ARG_MUST_BE_NULL
  __attribute__: add a few missing format attributes
 add-patch.c   | 1 +
 attr.h        | 2 ++
 config.c      | 1 -
 hook.h        | 1 +
 mem-pool.h    | 1 +
 run-command.c | 3 ++-
 scalar.c      | 2 ++
 trace2.h      | 1 +
 wt-status.c   | 1 +
 9 files changed, 11 insertions(+), 2 deletions(-)
-- 
2.45.2-445-g1b76f06508
Junio C Hamano· Jun 8, 2024, 18:37 UTC · re: Junio C Hamano · lore

[PATCH 1/4] __attribute__: trace2_region_enter_printf() is like "printf"

The last part of the parameter list the function takes is like parameters to printf. mark it as such.

An existing call that formats a value of type size_t using "%d" was found by the compiler with the help with this annotation; fix it.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 run-command.c | 3 ++-
 trace2.h      | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
Show changes to 2 files +3 −1

run-command.c, trace2.h

diff --git a/run-command.c b/run-command.c
index 1b821042b4..ec2c12e98b 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1753,7 +1753,8 @@ void run_processes_parallel(const struct run_process_parallel_opts *opts)
 
 	if (do_trace2)
 		trace2_region_enter_printf(tr2_category, tr2_label, NULL,
-					   "max:%d", opts->processes);
+					   "max:%"PRIuMAX,
+					   (uintmax_t)opts->processes);
 
 	pp_init(&pp, opts, &pp_sig);
 	while (1) {
diff --git a/trace2.h b/trace2.h
index 1f0669bbd2..19e04bf040 100644
--- a/trace2.h
+++ b/trace2.h
@@ -390,6 +390,7 @@ void trace2_region_enter_printf_va_fl(const char *file, int line,
 	trace2_region_enter_printf_va_fl(__FILE__, __LINE__, (category), \
 					 (label), (repo), (fmt), (ap))
 
+__attribute__((format (printf, 6, 7)))
 void trace2_region_enter_printf_fl(const char *file, int line,
 				   const char *category, const char *label,
 				   const struct repository *repo,
-- 
2.45.2-445-g1b76f06508
Patrick Steinhardt· Jun 10, 2024, 07:01 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/4] __attribute__: trace2_region_enter_printf() is like "printf"

On Sat, Jun 08, 2024 at 11:37:44AM -0700, Junio C Hamano wrote:
> The last part of the parameter list the function takes is like
> parameters to printf. mark it as such.
s/mark/Mark, or convert the dot to a semicolon.
> An existing call that formats a value of type size_t using "%d" was
> found by the compiler with the help with this annotation; fix it.
Makes sense, as do all the other patches in this series.
Patrick
Junio C Hamano· Jun 10, 2024, 16:15 UTC · re: Patrick Steinhardt · lore

Re: [PATCH 1/4] __attribute__: trace2_region_enter_printf() is like "printf"

Patrick Steinhardt <ps@pks.im> writes:
Show 10 quoted lines
> On Sat, Jun 08, 2024 at 11:37:44AM -0700, Junio C Hamano wrote:
>> The last part of the parameter list the function takes is like
>> parameters to printf. mark it as such.
>
> s/mark/Mark, or convert the dot to a semicolon.
>
>> An existing call that formats a value of type size_t using "%d" was
>> found by the compiler with the help with this annotation; fix it.
>
> Makes sense, as do all the other patches in this series.
Thanks, will amend.
Junio C Hamano· Jun 8, 2024, 18:37 UTC · re: Junio C Hamano · lore

[PATCH 2/4] __attribute__: remove redundant attribute declaration for git_die_config()

The convention is to declare the function attribute to an extern function together with its declaration in the header file, without repeating the attribute declaration with its definition in the .c source file (a file-scope static function declares its attribute together with its definition in the .c file it is defined, as there is no other place to do so).

The definition of git_die_config() in config.c did not follow the convention and had its attribute declared with both its declaration in the header and its definition in the .c source file.

Remove the one in the config.c to match everybody else.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 config.c | 1 -
 1 file changed, 1 deletion(-)
Show changes to config.c +0 −1
diff --git a/config.c b/config.c
index abce05b774..ea355f28ec 100644
--- a/config.c
+++ b/config.c
@@ -2844,7 +2844,6 @@ void git_die_config_linenr(const char *key, const char *filename, int linenr)
 		    key, filename, linenr);
 }
 
-NORETURN __attribute__((format(printf, 2, 3)))
 void git_die_config(const char *key, const char *err, ...)
 {
 	const struct string_list *values;
-- 
2.45.2-445-g1b76f06508
Junio C Hamano· Jun 8, 2024, 18:37 UTC · re: Junio C Hamano · lore

[PATCH 3/4] __attribute__: mark some functions with LAST_ARG_MUST_BE_NULL

Some varargs functions that use NULL-terminated parameter list were missing __attributes__ ((sentinel)) aka LAST_ARG_MUST_BE_NULL.

Add them.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 add-patch.c | 1 +
 attr.h      | 2 ++
 hook.h      | 1 +
 scalar.c    | 1 +
 4 files changed, 5 insertions(+)
Show changes to 4 files +5 −0

add-patch.c, attr.h, hook.h, scalar.c

diff --git a/add-patch.c b/add-patch.c
index 814de57c4a..d8ea05ff10 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -299,6 +299,7 @@ static void err(struct add_p_state *s, const char *fmt, ...)
 	va_end(args);
 }
 
+LAST_ARG_MUST_BE_NULL
 static void setup_child_process(struct add_p_state *s,
 				struct child_process *cp, ...)
 {
diff --git a/attr.h b/attr.h
index e7cc318b0c..bb33b60880 100644
--- a/attr.h
+++ b/attr.h
@@ -190,6 +190,8 @@ struct attr_check {
 };
 
 struct attr_check *attr_check_alloc(void);
+
+LAST_ARG_MUST_BE_NULL
 struct attr_check *attr_check_initl(const char *, ...);
 struct attr_check *attr_check_dup(const struct attr_check *check);
 
diff --git a/hook.h b/hook.h
index 19ab9a5806..6511525aeb 100644
--- a/hook.h
+++ b/hook.h
@@ -86,5 +86,6 @@ int run_hooks(const char *hook_name);
  * argument. These things will be used as positional arguments to the
  * hook. This function behaves like the old run_hook_le() API.
  */
+LAST_ARG_MUST_BE_NULL
 int run_hooks_l(const char *hook_name, ...);
 #endif
diff --git a/scalar.c b/scalar.c
index 331b91dbdb..62dd77aaec 100644
--- a/scalar.c
+++ b/scalar.c
@@ -70,6 +70,7 @@ static void setup_enlistment_directory(int argc, const char **argv,
 	strbuf_release(&path);
 }
 
+LAST_ARG_MUST_BE_NULL
 static int run_git(const char *arg, ...)
 {
 	struct child_process cmd = CHILD_PROCESS_INIT;
-- 
2.45.2-445-g1b76f06508
Junio C Hamano· Jun 8, 2024, 18:37 UTC · re: Junio C Hamano · lore

[PATCH 4/4] __attribute__: add a few missing format attributes

A public function mem_pool_strfmt() takes printf like parameters, but is not given an attribute as such. Also a few file-scope static functions were missing their format attribute.

Add them.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 mem-pool.h  | 1 +
 scalar.c    | 1 +
 wt-status.c | 1 +
 3 files changed, 3 insertions(+)
Show changes to 3 files +3 −0

mem-pool.h, scalar.c, wt-status.c

diff --git a/mem-pool.h b/mem-pool.h
index d1c66413ec..321d86a63c 100644
--- a/mem-pool.h
+++ b/mem-pool.h
@@ -50,6 +50,7 @@ char *mem_pool_strndup(struct mem_pool *pool, const char *str, size_t len);
 /*
  * Allocate memory from the memory pool and format a string into it.
  */
+__attribute__((format (printf, 2, 3)))
 char *mem_pool_strfmt(struct mem_pool *pool, const char *fmt, ...);
 
 /*
diff --git a/scalar.c b/scalar.c
index 62dd77aaec..a8318078c9 100644
--- a/scalar.c
+++ b/scalar.c
@@ -289,6 +289,7 @@ static int unregister_dir(void)
 }
 
 /* printf-style interface, expects `<key>=<value>` argument */
+__attribute__((format (printf, 1, 2)))
 static int set_config(const char *fmt, ...)
 {
 	struct strbuf buf = STRBUF_INIT;
diff --git a/wt-status.c b/wt-status.c
index ff4be071ca..c4dac01999 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -126,6 +126,7 @@ void status_printf(struct wt_status *s, const char *color,
 	va_end(ap);
 }
 
+__attribute__((format (printf, 3, 4)))
 static void status_printf_more(struct wt_status *s, const char *color,
 			       const char *fmt, ...)
 {
-- 
2.45.2-445-g1b76f06508
Jeff King· Jun 11, 2024, 08:17 UTC · re: Junio C Hamano · lore

Re: [PATCH 0/4] varargs functions with __attributes__(())

On Sat, Jun 08, 2024 at 11:37:43AM -0700, Junio C Hamano wrote:
Show 9 quoted lines
> There are several varargs functions that take either NULL-terminated
> list of parameters, or printf-like format followed by list of
> parameters, that are not declared as such with __attributes__(()).
> 
> Adding such a missing attribute to trace2_region_enter_printf()
> revealed that an existing call to it was trying to format a value of
> type size_t using "%d", which is not such an excellent idea.  Other
> functions that were lacking attributes fortunately did not have any
> broken existing callers.
Great, I am happy to see these. I assume you found them all by grepping?

I wonder if there is a way to convince the compiler (or coccinelle) to complain about any varargs function that does not have one of our usual annotations. It's possible to have other conventions (e.g., an "int" up front specifying the number of entries) but in practice I doubt we would ever use one.

Still, I suspect the answer is probably "no", there is not an easy way to do it.

-Peff
Junio C Hamano· Jun 11, 2024, 15:17 UTC · re: Jeff King · lore

Re: [PATCH 0/4] varargs functions with __attributes__(())

Jeff King <peff@peff.net> writes:
Show 22 quoted lines
> On Sat, Jun 08, 2024 at 11:37:43AM -0700, Junio C Hamano wrote:
>
>> There are several varargs functions that take either NULL-terminated
>> list of parameters, or printf-like format followed by list of
>> parameters, that are not declared as such with __attributes__(()).
>> 
>> Adding such a missing attribute to trace2_region_enter_printf()
>> revealed that an existing call to it was trying to format a value of
>> type size_t using "%d", which is not such an excellent idea.  Other
>> functions that were lacking attributes fortunately did not have any
>> broken existing callers.
>
> Great, I am happy to see these. I assume you found them all by grepping?
>
> I wonder if there is a way to convince the compiler (or coccinelle) to
> complain about any varargs function that does not have one of our
> usual annotations. It's possible to have other conventions (e.g., an
> "int" up front specifying the number of entries) but in practice I doubt
> we would ever use one.
>
> Still, I suspect the answer is probably "no", there is not an easy way
> to do it.

I just went from grepping for fixed "...)" in *.[ch] files. I do admit I wished some form of automation, but didn't come up with one.

I was happy that the exercise found a real bug ;-) I started it only as a clean-up topic.

← back to recent threads