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

9 messages from 2024-06-08 to 2024-06-11. Participants: Junio C Hamano, Patrick Steinhardt, Jeff King.
Thread: https://gitlist.dev/t/61607

## Junio C Hamano, 2024-06-08 18:37

Subject: [PATCH 0/4] varargs functions with __attributes__(())
Message-ID: <20240608183747.2084294-1-gitster@pobox.com>
URL: https://gitlist.dev/e/20240608183747.2084294-1-gitster%40pobox.com

```
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, 2024-06-08 18:37

Subject: [PATCH 1/4] __attribute__: trace2_region_enter_printf() is like "printf"
Message-ID: <20240608183747.2084294-2-gitster@pobox.com>
URL: https://gitlist.dev/e/20240608183747.2084294-2-gitster%40pobox.com
In-Reply-To: <20240608183747.2084294-1-gitster@pobox.com>

```
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(-)

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


```

## Junio C Hamano, 2024-06-08 18:37

Subject: [PATCH 2/4] __attribute__: remove redundant attribute declaration for git_die_config()
Message-ID: <20240608183747.2084294-3-gitster@pobox.com>
URL: https://gitlist.dev/e/20240608183747.2084294-3-gitster%40pobox.com
In-Reply-To: <20240608183747.2084294-1-gitster@pobox.com>

```
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(-)

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, 2024-06-08 18:37

Subject: [PATCH 3/4] __attribute__: mark some functions with LAST_ARG_MUST_BE_NULL
Message-ID: <20240608183747.2084294-4-gitster@pobox.com>
URL: https://gitlist.dev/e/20240608183747.2084294-4-gitster%40pobox.com
In-Reply-To: <20240608183747.2084294-1-gitster@pobox.com>

```
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(+)

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, 2024-06-08 18:37

Subject: [PATCH 4/4] __attribute__: add a few missing format attributes
Message-ID: <20240608183747.2084294-5-gitster@pobox.com>
URL: https://gitlist.dev/e/20240608183747.2084294-5-gitster%40pobox.com
In-Reply-To: <20240608183747.2084294-1-gitster@pobox.com>

```
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(+)

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


```

## Patrick Steinhardt, 2024-06-10 07:01

Subject: Re: [PATCH 1/4] __attribute__: trace2_region_enter_printf() is like "printf"
Message-ID: <ZmakwSVBXbjfRpUi@tanuki>
URL: https://gitlist.dev/e/ZmakwSVBXbjfRpUi%40tanuki
In-Reply-To: <20240608183747.2084294-2-gitster@pobox.com>

```
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, 2024-06-10 16:15

Subject: Re: [PATCH 1/4] __attribute__: trace2_region_enter_printf() is like "printf"
Message-ID: <xmqqy17c4vw7.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqy17c4vw7.fsf%40gitster.g
In-Reply-To: <ZmakwSVBXbjfRpUi@tanuki>

```
Patrick Steinhardt <ps@pks.im> writes:

> 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.

```

## Jeff King, 2024-06-11 08:17

Subject: Re: [PATCH 0/4] varargs functions with __attributes__(())
Message-ID: <20240611081735.GI3248245@coredump.intra.peff.net>
URL: https://gitlist.dev/e/20240611081735.GI3248245%40coredump.intra.peff.net
In-Reply-To: <20240608183747.2084294-1-gitster@pobox.com>

```
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.

-Peff

```

## Junio C Hamano, 2024-06-11 15:17

Subject: Re: [PATCH 0/4] varargs functions with __attributes__(())
Message-ID: <xmqqcyony0ej.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqcyony0ej.fsf%40gitster.g
In-Reply-To: <20240611081735.GI3248245@coredump.intra.peff.net>

```
Jeff King <peff@peff.net> writes:

> 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.

```
