Skip to content

Commit 02e5ba4

Browse files
peffgitster
authored andcommitted
config: handle lack of newline at end of file better
The config parsing routines use the static global 'config_file' to store the FILE* pointing to the current config file being parsed. The function get_next_char() automatically converts an EOF on this file to a newline for the convenience of its callers, and it sets config_file to NULL to indicate that EOF was reached. This throws away useful information, though, since some routines want to call ftell on 'config_file' to find out exactly _where_ the routine ended. In the case of a key ending at EOF boundary, we ended up segfaulting in some cases (changing that key or adding another key in its section), or failing to provide the necessary newline (adding a new section). This patch adds a new flag to indicate EOF and uses that instead of setting config_file to NULL. It also makes sure to add newlines where necessary for truncated input. All three included tests fail without the patch. Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent c477553 commit 02e5ba4

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

config.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
static FILE *config_file;
1414
static const char *config_file_name;
1515
static int config_linenr;
16+
static int config_file_eof;
1617
static int zlib_compression_seen;
1718

1819
static int get_next_char(void)
@@ -34,7 +35,7 @@ static int get_next_char(void)
3435
if (c == '\n')
3536
config_linenr++;
3637
if (c == EOF) {
37-
config_file = NULL;
38+
config_file_eof = 1;
3839
c = '\n';
3940
}
4041
}
@@ -118,7 +119,7 @@ static int get_value(config_fn_t fn, char *name, unsigned int len)
118119
/* Get the full name */
119120
for (;;) {
120121
c = get_next_char();
121-
if (c == EOF)
122+
if (config_file_eof)
122123
break;
123124
if (!iskeychar(c))
124125
break;
@@ -182,7 +183,7 @@ static int get_base_var(char *name)
182183

183184
for (;;) {
184185
int c = get_next_char();
185-
if (c == EOF)
186+
if (config_file_eof)
186187
return -1;
187188
if (c == ']')
188189
return baselen;
@@ -205,8 +206,7 @@ static int git_parse_file(config_fn_t fn)
205206
for (;;) {
206207
int c = get_next_char();
207208
if (c == '\n') {
208-
/* EOF? */
209-
if (!config_file)
209+
if (config_file_eof)
210210
return 0;
211211
comment = 0;
212212
continue;
@@ -469,6 +469,7 @@ int git_config_from_file(config_fn_t fn, const char *filename)
469469
config_file = f;
470470
config_file_name = filename;
471471
config_linenr = 1;
472+
config_file_eof = 0;
472473
ret = git_parse_file(fn);
473474
fclose(f);
474475
config_file_name = NULL;
@@ -918,6 +919,9 @@ int git_config_set_multivar(const char* key, const char* value,
918919
contents, contents_sz,
919920
store.offset[i]-2, &new_line);
920921

922+
if (copy_end > 0 && contents[copy_end-1] != '\n')
923+
new_line = 1;
924+
921925
/* write the first part of the config */
922926
if (copy_end > copy_begin) {
923927
if (write_in_full(fd, contents + copy_begin,

t/t1303-wacky-config.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/sh
2+
3+
test_description='Test wacky input to git config'
4+
. ./test-lib.sh
5+
6+
setup() {
7+
(printf "[section]\n" &&
8+
printf " key = foo") >.git/config
9+
}
10+
11+
check() {
12+
echo "$2" >expected
13+
git config --get "$1" >actual
14+
git diff actual expected
15+
}
16+
17+
test_expect_success 'modify same key' '
18+
setup &&
19+
git config section.key bar &&
20+
check section.key bar
21+
'
22+
23+
test_expect_success 'add key in same section' '
24+
setup &&
25+
git config section.other bar &&
26+
check section.key foo &&
27+
check section.other bar
28+
'
29+
30+
test_expect_success 'add key in different section' '
31+
setup &&
32+
git config section2.key bar &&
33+
check section.key foo &&
34+
check section2.key bar
35+
'
36+
37+
test_done

0 commit comments

Comments
 (0)