path: root/string-list.h
diff options
authorMichael Haggerty <>2017-09-20 05:27:05 (GMT)
committerJunio C Hamano <>2017-09-20 05:41:08 (GMT)
commitac7da78ede468315ba22d9ee1265b61a744371ee (patch)
treef1ed610d69399db07f0af1ce4337a8bb89a6cc74 /string-list.h
parent94c9fd268d4287f6fbfef84793288479905a7e48 (diff)
for_each_string_list_item: avoid undefined behavior for empty list
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; /* NULL */ item < (list)->items + (list)->nr; /* NULL + 0 */ ++item) Even though this probably works almost everywhere, it is undefined behavior, and it could plausibly cause highly-optimizing compilers to misbehave. C99 section 6.5.6 paragraph 8 explains: If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. and ( a null pointer does not point to anything. Guard the loop with a NULL check to make the intent crystal clear to even the most pedantic compiler. A suitably clever compiler could let the NULL check only run in the first iteration, but regardless, this overhead is likely to be dwarfed by the work to be done on each item. This problem was noticed by Coverity. [jn: using a NULL check instead of a placeholder empty list; fleshed out the commit message based on mailing list discussion] Signed-off-by: Michael Haggerty <> Signed-off-by: Jonathan Nieder <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'string-list.h')
1 files changed, 4 insertions, 2 deletions
diff --git a/string-list.h b/string-list.h
index 29bfb7a..79ae567 100644
--- a/string-list.h
+++ b/string-list.h
@@ -32,8 +32,10 @@ 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)
+#define for_each_string_list_item(item,list) \
+ for (item = (list)->items; \
+ item && item < (list)->items + (list)->nr; \
+ ++item)
* Apply want to each item in list, retaining only the ones for which