Skip to content

Commit d699e27

Browse files
committed
Merge branch 'tb/ban-strtok'
Mark strtok() and strtok_r() to be banned. * tb/ban-strtok: banned.h: mark `strtok()` and `strtok_r()` as banned t/helper/test-json-writer.c: avoid using `strtok()` t/helper/test-oidmap.c: avoid using `strtok()` t/helper/test-hashmap.c: avoid using `strtok()` string-list: introduce `string_list_setlen()` string-list: multi-delimiter `string_list_split_in_place()`
2 parents cf85f4b + 60ff56f commit d699e27

File tree

12 files changed

+161
-51
lines changed

12 files changed

+161
-51
lines changed

banned.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#define strncpy(x,y,n) BANNED(strncpy)
1919
#undef strncat
2020
#define strncat(x,y,n) BANNED(strncat)
21+
#undef strtok
22+
#define strtok(x,y) BANNED(strtok)
23+
#undef strtok_r
24+
#define strtok_r(x,y,z) BANNED(strtok_r)
2125

2226
#undef sprintf
2327
#undef vsprintf

builtin/gc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,11 +1685,11 @@ static int get_schedule_cmd(const char **cmd, int *is_available)
16851685
if (is_available)
16861686
*is_available = 0;
16871687

1688-
string_list_split_in_place(&list, testing, ',', -1);
1688+
string_list_split_in_place(&list, testing, ",", -1);
16891689
for_each_string_list_item(item, &list) {
16901690
struct string_list pair = STRING_LIST_INIT_NODUP;
16911691

1692-
if (string_list_split_in_place(&pair, item->string, ':', 2) != 2)
1692+
if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
16931693
continue;
16941694

16951695
if (!strcmp(*cmd, pair.items[0].string)) {

diff.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
139139
int i;
140140

141141
if (*params_copy)
142-
string_list_split_in_place(&params, params_copy, ',', -1);
142+
string_list_split_in_place(&params, params_copy, ",", -1);
143143
for (i = 0; i < params.nr; i++) {
144144
const char *p = params.items[i].string;
145145
if (!strcmp(p, "changes")) {

notes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ void string_list_add_refs_from_colon_sep(struct string_list *list,
964964
char *globs_copy = xstrdup(globs);
965965
int i;
966966

967-
string_list_split_in_place(&split, globs_copy, ':', -1);
967+
string_list_split_in_place(&split, globs_copy, ":", -1);
968968
string_list_remove_empty_items(&split, 0);
969969

970970
for (i = 0; i < split.nr; i++)

refs/packed-backend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs)
651651
snapshot->buf,
652652
snapshot->eof - snapshot->buf);
653653

654-
string_list_split_in_place(&traits, p, ' ', -1);
654+
string_list_split_in_place(&traits, p, " ", -1);
655655

656656
if (unsorted_string_list_has_string(&traits, "fully-peeled"))
657657
snapshot->peeled = PEELED_FULLY;

string-list.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ void string_list_clear_func(struct string_list *list, string_list_clear_func_t c
203203
list->nr = list->alloc = 0;
204204
}
205205

206+
void string_list_setlen(struct string_list *list, size_t nr)
207+
{
208+
if (list->strdup_strings)
209+
BUG("cannot setlen a string_list which owns its entries");
210+
if (nr > list->nr)
211+
BUG("cannot grow a string_list with setlen");
212+
list->nr = nr;
213+
}
214+
206215
struct string_list_item *string_list_append_nodup(struct string_list *list,
207216
char *string)
208217
{
@@ -301,7 +310,7 @@ int string_list_split(struct string_list *list, const char *string,
301310
}
302311

303312
int string_list_split_in_place(struct string_list *list, char *string,
304-
int delim, int maxsplit)
313+
const char *delim, int maxsplit)
305314
{
306315
int count = 0;
307316
char *p = string, *end;
@@ -315,7 +324,7 @@ int string_list_split_in_place(struct string_list *list, char *string,
315324
string_list_append(list, p);
316325
return count;
317326
}
318-
end = strchr(p, delim);
327+
end = strpbrk(p, delim);
319328
if (end) {
320329
*end = '\0';
321330
string_list_append(list, p);

string-list.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,16 @@ typedef void (*string_list_clear_func_t)(void *p, const char *str);
134134
/** Call a custom clear function on each util pointer */
135135
void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);
136136

137+
/*
138+
* Set the length of a string_list to `nr`, provided that (a) `list`
139+
* does not own its own storage, and (b) that `nr` is no larger than
140+
* `list->nr`.
141+
*
142+
* Useful when "shrinking" `list` to write over existing entries that
143+
* are no longer used without reallocating.
144+
*/
145+
void string_list_setlen(struct string_list *list, size_t nr);
146+
137147
/**
138148
* Apply `func` to each item. If `func` returns nonzero, the
139149
* iteration aborts and the return value is propagated.
@@ -270,5 +280,5 @@ int string_list_split(struct string_list *list, const char *string,
270280
* list->strdup_strings must *not* be set.
271281
*/
272282
int string_list_split_in_place(struct string_list *list, char *string,
273-
int delim, int maxsplit);
283+
const char *delim, int maxsplit);
274284
#endif /* STRING_LIST_H */

t/helper/test-hashmap.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "git-compat-util.h"
33
#include "hashmap.h"
44
#include "strbuf.h"
5+
#include "string-list.h"
56

67
struct test_entry
78
{
@@ -150,6 +151,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
150151
*/
151152
int cmd__hashmap(int argc, const char **argv)
152153
{
154+
struct string_list parts = STRING_LIST_INIT_NODUP;
153155
struct strbuf line = STRBUF_INIT;
154156
int icase;
155157
struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
@@ -159,21 +161,26 @@ int cmd__hashmap(int argc, const char **argv)
159161

160162
/* process commands from stdin */
161163
while (strbuf_getline(&line, stdin) != EOF) {
162-
char *cmd, *p1 = NULL, *p2 = NULL;
164+
char *cmd, *p1, *p2;
163165
unsigned int hash = 0;
164166
struct test_entry *entry;
165167

166168
/* break line into command and up to two parameters */
167-
cmd = strtok(line.buf, DELIM);
169+
string_list_setlen(&parts, 0);
170+
string_list_split_in_place(&parts, line.buf, DELIM, 2);
171+
string_list_remove_empty_items(&parts, 0);
172+
168173
/* ignore empty lines */
169-
if (!cmd || *cmd == '#')
174+
if (!parts.nr)
175+
continue;
176+
if (!*parts.items[0].string || *parts.items[0].string == '#')
170177
continue;
171178

172-
p1 = strtok(NULL, DELIM);
173-
if (p1) {
179+
cmd = parts.items[0].string;
180+
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
181+
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
182+
if (p1)
174183
hash = icase ? strihash(p1) : strhash(p1);
175-
p2 = strtok(NULL, DELIM);
176-
}
177184

178185
if (!strcmp("add", cmd) && p1 && p2) {
179186

@@ -260,6 +267,7 @@ int cmd__hashmap(int argc, const char **argv)
260267
}
261268
}
262269

270+
string_list_clear(&parts, 0);
263271
strbuf_release(&line);
264272
hashmap_clear_and_free(&map, struct test_entry, ent);
265273
return 0;

t/helper/test-json-writer.c

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "test-tool.h"
22
#include "json-writer.h"
3+
#include "string-list.h"
34

45
static const char *expect_obj1 = "{\"a\":\"abc\",\"b\":42,\"c\":true}";
56
static const char *expect_obj2 = "{\"a\":-1,\"b\":2147483647,\"c\":0}";
@@ -394,35 +395,41 @@ static int unit_tests(void)
394395
return 0;
395396
}
396397

397-
static void get_s(int line_nr, char **s_in)
398+
struct line {
399+
struct string_list *parts;
400+
size_t consumed_nr;
401+
int nr;
402+
};
403+
404+
static void get_s(struct line *line, char **s_in)
398405
{
399-
*s_in = strtok(NULL, " ");
400-
if (!*s_in)
401-
die("line[%d]: expected: <s>", line_nr);
406+
if (line->consumed_nr > line->parts->nr)
407+
die("line[%d]: expected: <s>", line->nr);
408+
*s_in = line->parts->items[line->consumed_nr++].string;
402409
}
403410

404-
static void get_i(int line_nr, intmax_t *s_in)
411+
static void get_i(struct line *line, intmax_t *s_in)
405412
{
406413
char *s;
407414
char *endptr;
408415

409-
get_s(line_nr, &s);
416+
get_s(line, &s);
410417

411418
*s_in = strtol(s, &endptr, 10);
412419
if (*endptr || errno == ERANGE)
413-
die("line[%d]: invalid integer value", line_nr);
420+
die("line[%d]: invalid integer value", line->nr);
414421
}
415422

416-
static void get_d(int line_nr, double *s_in)
423+
static void get_d(struct line *line, double *s_in)
417424
{
418425
char *s;
419426
char *endptr;
420427

421-
get_s(line_nr, &s);
428+
get_s(line, &s);
422429

423430
*s_in = strtod(s, &endptr);
424431
if (*endptr || errno == ERANGE)
425-
die("line[%d]: invalid float value", line_nr);
432+
die("line[%d]: invalid float value", line->nr);
426433
}
427434

428435
static int pretty;
@@ -453,6 +460,7 @@ static char *get_trimmed_line(char *buf, int buf_size)
453460

454461
static int scripted(void)
455462
{
463+
struct string_list parts = STRING_LIST_INIT_NODUP;
456464
struct json_writer jw = JSON_WRITER_INIT;
457465
char buf[MAX_LINE_LENGTH];
458466
char *line;
@@ -470,66 +478,77 @@ static int scripted(void)
470478
die("expected first line to be 'object' or 'array'");
471479

472480
while ((line = get_trimmed_line(buf, MAX_LINE_LENGTH)) != NULL) {
481+
struct line state = { 0 };
473482
char *verb;
474483
char *key;
475484
char *s_value;
476485
intmax_t i_value;
477486
double d_value;
478487

479-
line_nr++;
488+
state.parts = &parts;
489+
state.nr = ++line_nr;
490+
491+
/* break line into command and zero or more tokens */
492+
string_list_setlen(&parts, 0);
493+
string_list_split_in_place(&parts, line, " ", -1);
494+
string_list_remove_empty_items(&parts, 0);
495+
496+
/* ignore empty lines */
497+
if (!parts.nr || !*parts.items[0].string)
498+
continue;
480499

481-
verb = strtok(line, " ");
500+
verb = parts.items[state.consumed_nr++].string;
482501

483502
if (!strcmp(verb, "end")) {
484503
jw_end(&jw);
485504
}
486505
else if (!strcmp(verb, "object-string")) {
487-
get_s(line_nr, &key);
488-
get_s(line_nr, &s_value);
506+
get_s(&state, &key);
507+
get_s(&state, &s_value);
489508
jw_object_string(&jw, key, s_value);
490509
}
491510
else if (!strcmp(verb, "object-int")) {
492-
get_s(line_nr, &key);
493-
get_i(line_nr, &i_value);
511+
get_s(&state, &key);
512+
get_i(&state, &i_value);
494513
jw_object_intmax(&jw, key, i_value);
495514
}
496515
else if (!strcmp(verb, "object-double")) {
497-
get_s(line_nr, &key);
498-
get_i(line_nr, &i_value);
499-
get_d(line_nr, &d_value);
516+
get_s(&state, &key);
517+
get_i(&state, &i_value);
518+
get_d(&state, &d_value);
500519
jw_object_double(&jw, key, i_value, d_value);
501520
}
502521
else if (!strcmp(verb, "object-true")) {
503-
get_s(line_nr, &key);
522+
get_s(&state, &key);
504523
jw_object_true(&jw, key);
505524
}
506525
else if (!strcmp(verb, "object-false")) {
507-
get_s(line_nr, &key);
526+
get_s(&state, &key);
508527
jw_object_false(&jw, key);
509528
}
510529
else if (!strcmp(verb, "object-null")) {
511-
get_s(line_nr, &key);
530+
get_s(&state, &key);
512531
jw_object_null(&jw, key);
513532
}
514533
else if (!strcmp(verb, "object-object")) {
515-
get_s(line_nr, &key);
534+
get_s(&state, &key);
516535
jw_object_inline_begin_object(&jw, key);
517536
}
518537
else if (!strcmp(verb, "object-array")) {
519-
get_s(line_nr, &key);
538+
get_s(&state, &key);
520539
jw_object_inline_begin_array(&jw, key);
521540
}
522541
else if (!strcmp(verb, "array-string")) {
523-
get_s(line_nr, &s_value);
542+
get_s(&state, &s_value);
524543
jw_array_string(&jw, s_value);
525544
}
526545
else if (!strcmp(verb, "array-int")) {
527-
get_i(line_nr, &i_value);
546+
get_i(&state, &i_value);
528547
jw_array_intmax(&jw, i_value);
529548
}
530549
else if (!strcmp(verb, "array-double")) {
531-
get_i(line_nr, &i_value);
532-
get_d(line_nr, &d_value);
550+
get_i(&state, &i_value);
551+
get_d(&state, &d_value);
533552
jw_array_double(&jw, i_value, d_value);
534553
}
535554
else if (!strcmp(verb, "array-true"))
@@ -552,6 +571,7 @@ static int scripted(void)
552571
printf("%s\n", jw.json.buf);
553572

554573
jw_release(&jw);
574+
string_list_clear(&parts, 0);
555575
return 0;
556576
}
557577

t/helper/test-oidmap.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "oidmap.h"
55
#include "setup.h"
66
#include "strbuf.h"
7+
#include "string-list.h"
78

89
/* key is an oid and value is a name (could be a refname for example) */
910
struct test_entry {
@@ -25,6 +26,7 @@ struct test_entry {
2526
*/
2627
int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
2728
{
29+
struct string_list parts = STRING_LIST_INIT_NODUP;
2830
struct strbuf line = STRBUF_INIT;
2931
struct oidmap map = OIDMAP_INIT;
3032

@@ -35,19 +37,24 @@ int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
3537

3638
/* process commands from stdin */
3739
while (strbuf_getline(&line, stdin) != EOF) {
38-
char *cmd, *p1 = NULL, *p2 = NULL;
40+
char *cmd, *p1, *p2;
3941
struct test_entry *entry;
4042
struct object_id oid;
4143

4244
/* break line into command and up to two parameters */
43-
cmd = strtok(line.buf, DELIM);
45+
string_list_setlen(&parts, 0);
46+
string_list_split_in_place(&parts, line.buf, DELIM, 2);
47+
string_list_remove_empty_items(&parts, 0);
48+
4449
/* ignore empty lines */
45-
if (!cmd || *cmd == '#')
50+
if (!parts.nr)
51+
continue;
52+
if (!*parts.items[0].string || *parts.items[0].string == '#')
4653
continue;
4754

48-
p1 = strtok(NULL, DELIM);
49-
if (p1)
50-
p2 = strtok(NULL, DELIM);
55+
cmd = parts.items[0].string;
56+
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
57+
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
5158

5259
if (!strcmp("put", cmd) && p1 && p2) {
5360

@@ -108,6 +115,7 @@ int cmd__oidmap(int argc UNUSED, const char **argv UNUSED)
108115
}
109116
}
110117

118+
string_list_clear(&parts, 0);
111119
strbuf_release(&line);
112120
oidmap_free(&map, 1);
113121
return 0;

0 commit comments

Comments
 (0)