Re: [PATCH v5 18/21] commit-graph: use string-list API for input
- From
Ævar Arnfjörð Bjarmason <avarab@gmail.com>
- Date
- Jun 6, 2018, 12:26 UTC
- Message-ID
- <87efhkyubq.fsf@evledraar.gmail.com>
- In-Reply-To
- <aa4c3a93-0c63-f424-db0b-0e451bbaa91e@gmail.com>
On Wed, Jun 06 2018, Derrick Stolee wrote:
Show 78 quoted lines
> On 6/6/2018 8:11 AM, Ævar Arnfjörð Bjarmason wrote:
>> On Wed, Jun 06 2018, Derrick Stolee wrote:
>>
>>> Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
>>> ---
>>> builtin/commit-graph.c | 39 +++++++++++++--------------------------
>>> commit-graph.c | 15 +++++++--------
>>> commit-graph.h | 7 +++----
>>> 3 files changed, 23 insertions(+), 38 deletions(-)
>>> diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
>>> index 3079cde6f9..d8eb8278b3 100644
>>> --- a/builtin/commit-graph.c
>>> +++ b/builtin/commit-graph.c
>>> @@ -118,13 +118,9 @@ static int graph_read(int argc, const char **argv)
>>>
>>> static int graph_write(int argc, const char **argv)
>>> {
>>> - const char **pack_indexes = NULL;
>>> - int packs_nr = 0;
>>> - const char **commit_hex = NULL;
>>> - int commits_nr = 0;
>>> - const char **lines = NULL;
>>> - int lines_nr = 0;
>>> - int lines_alloc = 0;
>>> + struct string_list *pack_indexes = NULL;
>>> + struct string_list *commit_hex = NULL;
>>> + struct string_list lines;
>>>
>>> static struct option builtin_commit_graph_write_options[] = {
>>> OPT_STRING(0, "object-dir", &opts.obj_dir,
>>> @@ -150,32 +146,23 @@ static int graph_write(int argc, const char **argv)
>>>
>>> if (opts.stdin_packs || opts.stdin_commits) {
>>> struct strbuf buf = STRBUF_INIT;
>>> - lines_nr = 0;
>>> - lines_alloc = 128;
>>> - ALLOC_ARRAY(lines, lines_alloc);
>>> -
>>> - while (strbuf_getline(&buf, stdin) != EOF) {
>>> - ALLOC_GROW(lines, lines_nr + 1, lines_alloc);
>>> - lines[lines_nr++] = strbuf_detach(&buf, NULL);
>>> - }
>>> -
>>> - if (opts.stdin_packs) {
>>> - pack_indexes = lines;
>>> - packs_nr = lines_nr;
>>> - }
>>> - if (opts.stdin_commits) {
>>> - commit_hex = lines;
>>> - commits_nr = lines_nr;
>>> - }
>>> + string_list_init(&lines, 0);
>>> +
>>> + while (strbuf_getline(&buf, stdin) != EOF)
>>> + string_list_append(&lines, strbuf_detach(&buf, NULL));
>>> +
>>> + if (opts.stdin_packs)
>>> + pack_indexes = &lines;
>>> + if (opts.stdin_commits)
>>> + commit_hex = &lines;
>>> }
>>>
>>> write_commit_graph(opts.obj_dir,
>>> pack_indexes,
>>> - packs_nr,
>>> commit_hex,
>>> - commits_nr,
>>> opts.append);
>>>
>>> + string_list_clear(&lines, 0);
>>> return 0;
>>> }
>> This results in an invalid free() & segfault because you're freeing
>> &lines which may not have been allocated by string_list_init().
>
> Good point. Did my tests not catch this? (seems it requires calling
> `git commit-graph write` with no `--stdin-packs` or
> `--stdin-commits`).Most of your tests (t5318-commit-graph.sh) segfaulted, but presumably you're on a more forgiving compiler/platform/options. I compiled with -O0 -g on clang 4.0.1-8 + Debian testing.
Show 38 quoted lines
>>
>> Monkeypatch on top which I used to fix it:
>>
>> diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
>> index 76423b3fa5..c7eb68aa3a 100644
>> --- a/builtin/commit-graph.c
>> +++ b/builtin/commit-graph.c
>> @@ -122,6 +122,7 @@ static int graph_write(int argc, const char **argv)
>> struct string_list *pack_indexes = NULL;
>> struct string_list *commit_hex = NULL;
>> struct string_list lines;
>> + int free_lines = 0;
>>
>> static struct option builtin_commit_graph_write_options[] = {
>> OPT_STRING(0, "object-dir", &opts.obj_dir,
>> @@ -155,6 +156,7 @@ static int graph_write(int argc, const char **argv)
>> if (opts.stdin_packs || opts.stdin_commits) {
>> struct strbuf buf = STRBUF_INIT;
>> string_list_init(&lines, 0);
>> + free_lines = 1;
>>
>> while (strbuf_getline(&buf, stdin) != EOF)
>> string_list_append(&lines, strbuf_detach(&buf, NULL));
>> @@ -170,7 +172,8 @@ static int graph_write(int argc, const char **argv)
>> commit_hex,
>> opts.append);
>>
>> - string_list_clear(&lines, 0);
>> + if (free_lines)
>> + string_list_clear(&lines, 0);
>> return 0;
>> }
>>
>> But probably having a pointer to the struct which is NULL etc. is
>> better.
>
> Wouldn't the easiest fix be to call `string_list_init(&lines, 0)`
> outside of any conditional?Sure that works too. We'd be doing the init when we don't need it, but it's not like this part is performance critical or anything...