If you pass a newly-initialized or newly-cleared `string_list` to
`for_each_string_list_item()`, then the latter does
for (
item = (list)->items; /* note, this is NULL */
item < (list)->items + (list)->nr; /* note: NULL + 0 */
++item)
Even though this probably works almost everywhere, it is undefined
behavior, and it could plausibly cause highly-optimizing compilers to
misbehave.
It would be a pain to have to change the signature of this macro, and
we'd prefer not to add overhead to each iteration of the loop. So
instead, whenever `list->items` is NULL, initialize `item` to point at
a dummy `string_list_item` created for the purpose.
This problem was noticed by Coverity.
Signed-off-by: Michael Haggerty <[email protected]>
---
Just a little thing I noticed in a Coverity report. This macro has
been broken since it was first introduced, in 2010.
This patch applies against maint. It is also available from my Git
fork [1] as branch `iter-empty-string-list`.
Michael
[1] https://github.com/mhagger/git
string-list.c | 2 ++
string-list.h | 7 +++++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/string-list.c b/string-list.c
index 806b4c8723..7eacf6037f 100644
--- a/string-list.c
+++ b/string-list.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "string-list.h"
+struct string_list_item dummy_string_list_item;
+
void string_list_init(struct string_list *list, int strdup_strings)
{
memset(list, 0, sizeof(*list));
diff --git a/string-list.h b/string-list.h
index 29bfb7ae45..79bb78d80a 100644
--- a/string-list.h
+++ b/string-list.h
@@ -32,8 +32,11 @@ void string_list_clear_func(struct string_list *list,
string_list_clear_func_t c
typedef int (*string_list_each_func_t)(struct string_list_item *, void *);
int for_each_string_list(struct string_list *list,
string_list_each_func_t, void *cb_data);
-#define for_each_string_list_item(item,list) \
- for (item = (list)->items; item < (list)->items + (list)->nr; ++item)
+extern struct string_list_item dummy_string_list_item;
+#define for_each_string_list_item(item,list) \
+ for (item = (list)->items ? (list)->items : &dummy_string_list_item; \
+ item < (list)->items + (list)->nr; \
+ ++item)
/*
* Apply want to each item in list, retaining only the ones for which
--
2.14.1