{"thread":{"id":"53968","subject":"[PATCH] upload-pack: use buffered I/O to talk to rev-list","startedAt":"2020-08-02T14:38:48Z","lastAt":"2020-08-13T09:01:13Z","messageCount":9,"participants":["René Scharfe","Chris Torek","Johannes Sixt","Christian Couder","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"402651","messageId":"6722ade6-971e-7ecc-e8f0-7f595ca0b0ff@web.de","threadId":"53968","inReplyTo":null,"subject":"[PATCH] upload-pack: use buffered I/O to talk to rev-list","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2020-08-02T14:38:43Z","receivedAt":"2020-08-02T14:38:48Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Like f0bca72dc77 (send-pack: use buffered I/O to talk to pack-objects,\n2016-06-08), significantly reduce the number of system calls and\nsimplify the code for sending object IDs to rev-list by using stdio's\nbuffering and handling errors after the loops.\n\nSigned-off-by: René Scharfe <l.s.r@web.de>\n---\n upload-pack.c | 21 +++++++--------------\n 1 file changed, 7 insertions(+), 14 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 86737410709..9f616c2c6a6 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -595,10 +595,9 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tstatic const char *argv[] = {\n \t\t\"rev-list\", \"--stdin\", NULL,\n \t};\n+\tFILE *cmd_in;\n \tstruct object *o;\n-\tchar namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */\n \tint i;\n-\tconst unsigned hexsz = the_hash_algo->hexsz;\n\n \tcmd->argv = argv;\n \tcmd->git_cmd = 1;\n@@ -616,8 +615,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tif (start_command(cmd))\n \t\tgoto error;\n\n-\tnamebuf[0] = '^';\n-\tnamebuf[hexsz + 1] = '\\n';\n+\tcmd_in = xfdopen(cmd->in, \"w\");\n+\n \tfor (i = get_max_object_index(); 0 < i; ) {\n \t\to = get_indexed_object(--i);\n \t\tif (!o)\n@@ -626,11 +625,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\t\to->flags &= ~TMP_MARK;\n \t\tif (!is_our_ref(o, allow_uor))\n \t\t\tcontinue;\n-\t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), hexsz);\n-\t\tif (write_in_full(cmd->in, namebuf, hexsz + 2) < 0)\n-\t\t\tgoto error;\n+\t\tfprintf(cmd_in, \"^%s\\n\", oid_to_hex(&o->oid));\n \t}\n-\tnamebuf[hexsz] = '\\n';\n \tfor (i = 0; i < src->nr; i++) {\n \t\to = src->objects[i].item;\n \t\tif (is_our_ref(o, allow_uor)) {\n@@ -640,12 +636,11 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\t}\n \t\tif (reachable && o->type == OBJ_COMMIT)\n \t\t\to->flags |= TMP_MARK;\n-\t\tmemcpy(namebuf, oid_to_hex(&o->oid), hexsz);\n-\t\tif (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)\n-\t\t\tgoto error;\n+\t\tfprintf(cmd_in, \"%s\\n\", oid_to_hex(&o->oid));\n \t}\n-\tclose(cmd->in);\n \tcmd->in = -1;\n+\tif (fclose(cmd_in))\n+\t\tgoto error;\n \tsigchain_pop(SIGPIPE);\n\n \treturn 0;\n@@ -653,8 +648,6 @@ static int do_reachable_revlist(struct child_process *cmd,\n error:\n \tsigchain_pop(SIGPIPE);\n\n-\tif (cmd->in >= 0)\n-\t\tclose(cmd->in);\n \tif (cmd->out >= 0)\n \t\tclose(cmd->out);\n \treturn -1;\n--\n2.28.0\n"},{"id":"402659","messageId":"CAPx1GvdJ-4Yyf7Vm1OdhaW2TZp77HOfGxoGw0R2fKfEuHQkqOg@mail.gmail.com","threadId":"53968","inReplyTo":"6722ade6-971e-7ecc-e8f0-7f595ca0b0ff@web.de","subject":"Re: [PATCH] upload-pack: use buffered I/O to talk to rev-list","fromName":"Chris Torek","fromEmail":"chris.torek@gmail.com","sentAt":"2020-08-02T16:03:23Z","receivedAt":"2020-08-02T16:11:19Z","isPatch":true,"sender":{"key":"chris.torek@gmail.com","avatar":"https://avatars.githubusercontent.com/u/16826774?v=4"},"body":"One suggestion here:\n\nOn Sun, Aug 2, 2020 at 7:41 AM René Scharfe <l.s.r@web.de> wrote:\n> Like f0bca72dc77 (send-pack: use buffered I/O to talk to pack-objects,\n> 2016-06-08), significantly reduce the number of system calls and\n> simplify the code for sending object IDs to rev-list by using stdio's\n> buffering and handling errors after the loops.\n>\n> Signed-off-by: René Scharfe <l.s.r@web.de>\n> ---\n>  upload-pack.c | 21 +++++++--------------\n>  1 file changed, 7 insertions(+), 14 deletions(-)\n>\n> diff --git a/upload-pack.c b/upload-pack.c\n> index 86737410709..9f616c2c6a6 100644\n> --- a/upload-pack.c\n> +++ b/upload-pack.c\n\n[snip]\n\n> @@ -640,12 +636,11 @@ static int do_reachable_revlist(struct child_process *cmd,\n>                 }\n>                 if (reachable && o->type == OBJ_COMMIT)\n>                         o->flags |= TMP_MARK;\n> -               memcpy(namebuf, oid_to_hex(&o->oid), hexsz);\n> -               if (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)\n> -                       goto error;\n> +               fprintf(cmd_in, \"%s\\n\", oid_to_hex(&o->oid));\n\nThe fprintf() call here *can* return an error, e.g., if the\nconnection has died.  If it does, it should set things up so that\na later ferror(cmd_in) returns true.\n\n>         }\n> -       close(cmd->in);\n>         cmd->in = -1;\n> +       if (fclose(cmd_in))\n> +               goto error;\n\nThe fclose() call doesn't necessarily check ferror().  (The\nFreeBSD stdio in particular definitely does not.)  It might\nbe better to use:\n\n    failure = ferror(cmd_in);\n    failure |= fclose(cmd_in);\n    if (failure) ...\n\nhere, or similar.  (The temporary variable is not needed,\nbut someone might assume `if (ferror(fp) | fclose(fp))` is\na typo for `if (ferror(fp) || fclose(fp))`.)\n\n(Note: my sample isn't properly indented as gmail does not\nlet me insert tabs easily)\n\nChris\n"},{"id":"402680","messageId":"87c4ab84-8db5-bd62-af66-fd88f788827b@web.de","threadId":"53968","inReplyTo":"CAPx1GvdJ-4Yyf7Vm1OdhaW2TZp77HOfGxoGw0R2fKfEuHQkqOg@mail.gmail.com","subject":"Re: [PATCH] upload-pack: use buffered I/O to talk to rev-list","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2020-08-03T14:00:34Z","receivedAt":"2020-08-03T14:01:04Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 02.08.20 um 18:03 schrieb Chris Torek:\n> One suggestion here:\n>\n> On Sun, Aug 2, 2020 at 7:41 AM René Scharfe <l.s.r@web.de> wrote:\n>> Like f0bca72dc77 (send-pack: use buffered I/O to talk to pack-objects,\n>> 2016-06-08), significantly reduce the number of system calls and\n>> simplify the code for sending object IDs to rev-list by using stdio's\n>> buffering and handling errors after the loops.\n>>\n>> Signed-off-by: René Scharfe <l.s.r@web.de>\n>> ---\n>>  upload-pack.c | 21 +++++++--------------\n>>  1 file changed, 7 insertions(+), 14 deletions(-)\n>>\n>> diff --git a/upload-pack.c b/upload-pack.c\n>> index 86737410709..9f616c2c6a6 100644\n>> --- a/upload-pack.c\n>> +++ b/upload-pack.c\n>\n> [snip]\n>\n>> @@ -640,12 +636,11 @@ static int do_reachable_revlist(struct child_process *cmd,\n>>                 }\n>>                 if (reachable && o->type == OBJ_COMMIT)\n>>                         o->flags |= TMP_MARK;\n>> -               memcpy(namebuf, oid_to_hex(&o->oid), hexsz);\n>> -               if (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)\n>> -                       goto error;\n>> +               fprintf(cmd_in, \"%s\\n\", oid_to_hex(&o->oid));\n>\n> The fprintf() call here *can* return an error, e.g., if the\n> connection has died.  If it does, it should set things up so that\n> a later ferror(cmd_in) returns true.\n>\n>>         }\n>> -       close(cmd->in);\n>>         cmd->in = -1;\n>> +       if (fclose(cmd_in))\n>> +               goto error;\n>\n> The fclose() call doesn't necessarily check ferror().  (The\n> FreeBSD stdio in particular definitely does not.)  It might\n> be better to use:\n>\n>     failure = ferror(cmd_in);\n>     failure |= fclose(cmd_in);\n>     if (failure) ...\n>\n> here, or similar.  (The temporary variable is not needed,\n> but someone might assume `if (ferror(fp) | fclose(fp))` is\n> a typo for `if (ferror(fp) || fclose(fp))`.)\n\nThanks, didn't know that.  That's awful.  So the sentence \"The fclose()\nand fdclose() functions may also fail and set errno for any of the\nerrors specified for fflush(3).\" from the FreeBSD manpage for fclose(3)\nactually means that while it will flush, it is free to ignore any\nflush errors?\n\nOr do you mean that fflush() can succeed on a stream that has its error\nindicator set?\n\nIn any case, we'd then better add a function that flushes the buffer,\ncloses the stream and reports errors in its return code and errno --\ni.e. a sane fclose().\n\nRené\n\n"},{"id":"402690","messageId":"CAPx1Gvd7rULr-Z-mLDc2FCxyoepdMhK2t=j23-mr_6pvvHWynw@mail.gmail.com","threadId":"53968","inReplyTo":"87c4ab84-8db5-bd62-af66-fd88f788827b@web.de","subject":"Re: [PATCH] upload-pack: use buffered I/O to talk to rev-list","fromName":"Chris Torek","fromEmail":"chris.torek@gmail.com","sentAt":"2020-08-03T15:54:55Z","receivedAt":"2020-08-03T15:55:08Z","isPatch":true,"sender":{"key":"chris.torek@gmail.com","avatar":"https://avatars.githubusercontent.com/u/16826774?v=4"},"body":"On Mon, Aug 3, 2020 at 7:00 AM René Scharfe <l.s.r@web.de> wrote:\n>\n> Am 02.08.20 um 18:03 schrieb Chris Torek:\n> > The fclose() call doesn't necessarily check ferror().  (The\n> > FreeBSD stdio in particular definitely does not.)\n>\n> Thanks, didn't know that.  That's awful.  So the sentence \"The fclose()\n> and fdclose() functions may also fail and set errno for any of the\n> errors specified for fflush(3).\" from the FreeBSD manpage for fclose(3)\n> actually means that while it will flush, it is free to ignore any\n> flush errors?\n>\n> Or do you mean that fflush() can succeed on a stream that has its error\n> indicator set?\n\nThe latter.  You have to get particularly (un?)lucky here: say the\nbuffer size is n, and the *last* write operation (fprintf, whatever)\nfilled the buffer mod n and called fflush internally and that failed.\nThen at the time you call fclose() the buffer is empty.  There is\nnothing to flush, so we just get the result of the system's close()\ncall.\n\n> In any case, we'd then better add a function that flushes the buffer,\n> closes the stream and reports errors in its return code and errno --\n> i.e. a sane fclose().\n\nUnfortunately the global-variable nature of errno means it may be\nclobbered by the time you inspect it here, again with the same sort\nof issue above.  It might be nice if C's error conventions were more\nlike Go's, and stdio retained an earlier error, but this stuff all dates\nback to 16-bit \"int\" and 512-byte buffers and no room for nice stuff. :-)\n\nChris\n"},{"id":"402715","messageId":"4c7adb21-e47c-1d11-0974-8387b554eb9e@kdbg.org","threadId":"53968","inReplyTo":"CAPx1GvdJ-4Yyf7Vm1OdhaW2TZp77HOfGxoGw0R2fKfEuHQkqOg@mail.gmail.com","subject":"Re: [PATCH] upload-pack: use buffered I/O to talk to rev-list","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2020-08-03T18:15:41Z","receivedAt":"2020-08-03T18:15:46Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 02.08.20 um 18:03 schrieb Chris Torek:\n> One suggestion here:\n> \n> On Sun, Aug 2, 2020 at 7:41 AM René Scharfe <l.s.r@web.de> wrote:\n>> Like f0bca72dc77 (send-pack: use buffered I/O to talk to pack-objects,\n>> 2016-06-08), significantly reduce the number of system calls and\n>> simplify the code for sending object IDs to rev-list by using stdio's\n>> buffering and handling errors after the loops.\n>>\n>> Signed-off-by: René Scharfe <l.s.r@web.de>\n>> ---\n>>  upload-pack.c | 21 +++++++--------------\n>>  1 file changed, 7 insertions(+), 14 deletions(-)\n>>\n>> diff --git a/upload-pack.c b/upload-pack.c\n>> index 86737410709..9f616c2c6a6 100644\n>> --- a/upload-pack.c\n>> +++ b/upload-pack.c\n> \n> [snip]\n> \n>> @@ -640,12 +636,11 @@ static int do_reachable_revlist(struct child_process *cmd,\n>>                 }\n>>                 if (reachable && o->type == OBJ_COMMIT)\n>>                         o->flags |= TMP_MARK;\n>> -               memcpy(namebuf, oid_to_hex(&o->oid), hexsz);\n>> -               if (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)\n>> -                       goto error;\n>> +               fprintf(cmd_in, \"%s\\n\", oid_to_hex(&o->oid));\n> \n> The fprintf() call here *can* return an error, e.g., if the\n> connection has died.  If it does, it should set things up so that\n> a later ferror(cmd_in) returns true.\n\nTrue. We need an explicit test after each fprintf anyway because SIGPIPE\nmay be ignored, and then writing fails with EPIPE. On Windows, this is\ndoubly important because we do not have SIGPIPE at all (and always see\nEPIPE), but we see EPIPE only on the first failed write; subsequent\nwrites produce EINVAL.\n\n-- Hannes\n"},{"id":"403472","messageId":"cf395005-af63-f698-fe19-6c4b6f1a8a4b@web.de","threadId":"53968","inReplyTo":"6722ade6-971e-7ecc-e8f0-7f595ca0b0ff@web.de","subject":"[PATCH v2] upload-pack: use buffered I/O to talk to rev-list","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2020-08-12T16:52:55Z","receivedAt":"2020-08-12T16:53:05Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Like f0bca72dc77 (send-pack: use buffered I/O to talk to pack-objects,\n2016-06-08), significantly reduce the number of system calls and\nsimplify the code for sending object IDs to rev-list by using stdio's\nbuffering.\n\nTake care to handle errors immediately to get the correct error code,\nand to flush the buffer explicitly before closing the stream in order to\ncatch any write errors for these last bytes.\n\nHelped-by: Chris Torek <chris.torek@gmail.com>\nHelped-by: Johannes Sixt <j6t@kdbg.org>\n---\nChanges since v1:\n- Handle fprintf() errors immediately.\n- Call ferror() and fflush() explicitly before calling fclose().\n- Ignore fclose() errors, similar to the original code.\n- Initialize the stream pointer and use a NULL check in the error\n  handler to avoid a bogus compiler warning about it being used\n  without initialization.\n\n upload-pack.c | 22 ++++++++++------------\n 1 file changed, 10 insertions(+), 12 deletions(-)\n\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 80ad9a38d81..811fdd47b58 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -603,9 +603,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\t\"rev-list\", \"--stdin\", NULL,\n \t};\n \tstruct object *o;\n-\tchar namebuf[GIT_MAX_HEXSZ + 2]; /* ^ + hash + LF */\n+\tFILE *cmd_in = NULL;\n \tint i;\n-\tconst unsigned hexsz = the_hash_algo->hexsz;\n\n \tcmd->argv = argv;\n \tcmd->git_cmd = 1;\n@@ -623,8 +622,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n \tif (start_command(cmd))\n \t\tgoto error;\n\n-\tnamebuf[0] = '^';\n-\tnamebuf[hexsz + 1] = '\\n';\n+\tcmd_in = xfdopen(cmd->in, \"w\");\n+\n \tfor (i = get_max_object_index(); 0 < i; ) {\n \t\to = get_indexed_object(--i);\n \t\tif (!o)\n@@ -633,11 +632,9 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\t\to->flags &= ~TMP_MARK;\n \t\tif (!is_our_ref(o, allow_uor))\n \t\t\tcontinue;\n-\t\tmemcpy(namebuf + 1, oid_to_hex(&o->oid), hexsz);\n-\t\tif (write_in_full(cmd->in, namebuf, hexsz + 2) < 0)\n+\t\tif (fprintf(cmd_in, \"^%s\\n\", oid_to_hex(&o->oid)) < 0)\n \t\t\tgoto error;\n \t}\n-\tnamebuf[hexsz] = '\\n';\n \tfor (i = 0; i < src->nr; i++) {\n \t\to = src->objects[i].item;\n \t\tif (is_our_ref(o, allow_uor)) {\n@@ -647,11 +644,12 @@ static int do_reachable_revlist(struct child_process *cmd,\n \t\t}\n \t\tif (reachable && o->type == OBJ_COMMIT)\n \t\t\to->flags |= TMP_MARK;\n-\t\tmemcpy(namebuf, oid_to_hex(&o->oid), hexsz);\n-\t\tif (write_in_full(cmd->in, namebuf, hexsz + 1) < 0)\n+\t\tif (fprintf(cmd_in, \"%s\\n\", oid_to_hex(&o->oid)) < 0)\n \t\t\tgoto error;\n \t}\n-\tclose(cmd->in);\n+\tif (ferror(cmd_in) || fflush(cmd_in))\n+\t\tgoto error;\n+\tfclose(cmd_in);\n \tcmd->in = -1;\n \tsigchain_pop(SIGPIPE);\n\n@@ -660,8 +658,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n error:\n \tsigchain_pop(SIGPIPE);\n\n-\tif (cmd->in >= 0)\n-\t\tclose(cmd->in);\n+\tif (cmd_in)\n+\t\tfclose(cmd_in);\n \tif (cmd->out >= 0)\n \t\tclose(cmd->out);\n \treturn -1;\n--\n2.28.0\n"},{"id":"403525","messageId":"CAP8UFD1rDZOQSDWhc+xdEQVX+Umq-nE-sd-orgKZ3UWTWFHJhw@mail.gmail.com","threadId":"53968","inReplyTo":"cf395005-af63-f698-fe19-6c4b6f1a8a4b@web.de","subject":"Re: [PATCH v2] upload-pack: use buffered I/O to talk to rev-list","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2020-08-13T05:17:35Z","receivedAt":"2020-08-13T05:17:50Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Wed, Aug 12, 2020 at 6:54 PM René Scharfe <l.s.r@web.de> wrote:\n\n> -       close(cmd->in);\n> +       if (ferror(cmd_in) || fflush(cmd_in))\n> +               goto error;\n> +       fclose(cmd_in);\n>         cmd->in = -1;\n\nI wonder if setting cmd->in to -1 is still useful...\n\n>         sigchain_pop(SIGPIPE);\n>\n> @@ -660,8 +658,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n>  error:\n>         sigchain_pop(SIGPIPE);\n>\n> -       if (cmd->in >= 0)\n> -               close(cmd->in);\n> +       if (cmd_in)\n> +               fclose(cmd_in);\n\n...as we don't check cmd->in anymore at the end of the function, but\nwe now check cmd_in instead. So should cmd_in have been set to -1\ninstead of cmd->in?\n"},{"id":"403530","messageId":"866055fd-7857-3eb3-6dae-befc8f891994@web.de","threadId":"53968","inReplyTo":"CAP8UFD1rDZOQSDWhc+xdEQVX+Umq-nE-sd-orgKZ3UWTWFHJhw@mail.gmail.com","subject":"Re: [PATCH v2] upload-pack: use buffered I/O to talk to rev-list","fromName":"René Scharfe","fromEmail":"l.s.r@web.de","sentAt":"2020-08-13T05:57:20Z","receivedAt":"2020-08-13T05:58:39Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 13.08.20 um 07:17 schrieb Christian Couder:\n> On Wed, Aug 12, 2020 at 6:54 PM René Scharfe <l.s.r@web.de> wrote:\n>\n>> -       close(cmd->in);\n>> +       if (ferror(cmd_in) || fflush(cmd_in))\n>> +               goto error;\n>> +       fclose(cmd_in);\n>>         cmd->in = -1;\n>\n> I wonder if setting cmd->in to -1 is still useful...\n\nThe patch doesn't change its usefulness.  It probably was not necessary\nto begin with.\n\n>\n>>         sigchain_pop(SIGPIPE);\n>>\n\nThe next line right here (not shown in the diff) returns 0.\n\n>> @@ -660,8 +658,8 @@ static int do_reachable_revlist(struct child_process *cmd,\n>>  error:\n>>         sigchain_pop(SIGPIPE);\n>>\n>> -       if (cmd->in >= 0)\n>> -               close(cmd->in);\n>> +       if (cmd_in)\n>> +               fclose(cmd_in);\n>\n> ...as we don't check cmd->in anymore at the end of the function, but\n> we now check cmd_in instead. So should cmd_in have been set to -1\n> instead of cmd->in?\n\nThis error handler is not reached from the place that sets cmd->in back\nto -1.  It can be reached from a place where cmd_in is still NULL, so\nthis check is necessary and setting cmd_in to NULL above is not needed.\n\nRené\n"},{"id":"403533","messageId":"20200813090107.GB3092220@coredump.intra.peff.net","threadId":"53968","inReplyTo":"866055fd-7857-3eb3-6dae-befc8f891994@web.de","subject":"Re: [PATCH v2] upload-pack: use buffered I/O to talk to rev-list","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2020-08-13T09:01:07Z","receivedAt":"2020-08-13T09:01:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 13, 2020 at 07:57:20AM +0200, René Scharfe wrote:\n\n> Am 13.08.20 um 07:17 schrieb Christian Couder:\n> > On Wed, Aug 12, 2020 at 6:54 PM René Scharfe <l.s.r@web.de> wrote:\n> >\n> >> -       close(cmd->in);\n> >> +       if (ferror(cmd_in) || fflush(cmd_in))\n> >> +               goto error;\n> >> +       fclose(cmd_in);\n> >>         cmd->in = -1;\n> >\n> > I wonder if setting cmd->in to -1 is still useful...\n> \n> The patch doesn't change its usefulness.  It probably was not necessary\n> to begin with.\n\nRight. We exit immediately after setting it, but it's not clearly a dead\nload: the \"cmd\" struct is passed in from the caller. Prior to 2997178ee6\n(upload-pack: split check_unreachable() in two, prep for\nget_reachable_list(), 2016-06-12), it was part of a longer function\nwhich did have more error handling.\n\nBut after the split, has_unreachable() knows that it is always closed\nafter do_reachable_revlist() returns, so it never looks at cmd.in again.\nIt might be worth removing just to avoid confusion.\n\nI thought this also implied that the conditional close() in the error\nblock was not necessary, but it is. In the existing code we could \"goto\nerror\" from start_command() failing, before we ever assign to cmd->in.\nThe run-command API clears the struct in that case (so we'd see cmd->in\n== 0, and avoid closing).\n\n> >> -       if (cmd->in >= 0)\n> >> -               close(cmd->in);\n> >> +       if (cmd_in)\n> >> +               fclose(cmd_in);\n> >\n> > ...as we don't check cmd->in anymore at the end of the function, but\n> > we now check cmd_in instead. So should cmd_in have been set to -1\n> > instead of cmd->in?\n> \n> This error handler is not reached from the place that sets cmd->in back\n> to -1.  It can be reached from a place where cmd_in is still NULL, so\n> this check is necessary and setting cmd_in to NULL above is not needed.\n\nRight, that makes sense. Your NULL cmd_in is replacing the zero'd\ncmd->in from start_command().\n\nSo I think your patch is correct. It might be worth removing the \"-1\"\nassignment on top.\n\n-Peff\n"}]}