Message ID | 4a4e0aa0a49a54eea88f9c2d8e1db6a697012718.1653351786.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ci: fix windows-build with GCC v12.x | expand |
On Tue, May 24 2022, Johannes Schindelin via GitGitGadget wrote: > From: Johannes Schindelin <johannes.schindelin@gmx.de> > [...] > Let's drop that local variable and introduce a new flag in the slot that > is used to indicate that even while the slot is no longer in use, it is > still reserved until further notice. It is the responsibility of > `run_active_slot()` to clear that flag once it is done with that slot. > > Initial-patch-by: Junio C Hamano <gitster@pobox.com> Don't you mean by me? I.e. https://lore.kernel.org/git/patch-1.1-1cec367e805-20220126T212921Z-avarab@gmail.com/ This seems to be derived from that, or perhaps you just came up with something similar independently. Junio then came up with the smaller https://lore.kernel.org/git/xmqq8rv2nggn.fsf@gitster.g/
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes: > On Tue, May 24 2022, Johannes Schindelin via GitGitGadget wrote: > >> From: Johannes Schindelin <johannes.schindelin@gmx.de> >> [...] >> Let's drop that local variable and introduce a new flag in the slot that >> is used to indicate that even while the slot is no longer in use, it is >> still reserved until further notice. It is the responsibility of >> `run_active_slot()` to clear that flag once it is done with that slot. >> >> Initial-patch-by: Junio C Hamano <gitster@pobox.com> > > Don't you mean by me? > I.e. https://lore.kernel.org/git/patch-1.1-1cec367e805-20220126T212921Z-avarab@gmail.com/ Most likely, but this version is so distant from the "clear slot->finished before leaving run_active_slot()" Dscho and I were recently discussing, that I do not think it can be said to have been derived from that one. This is completely a different patch that makes different changes. The "clear slot->finished", by the way, is what I think is the right thing to do, especially that the objective is to squelch the false positive warning from a new compiler. If there is a way to annotate the line for the compiler to tell it not to warn about it, that would have been even better. > This seems to be derived from that, or perhaps you just came up with > something similar independently. Junio then came up with the smaller > https://lore.kernel.org/git/xmqq8rv2nggn.fsf@gitster.g/ I actually do not think so. Yours is revert of the existing fix the compiler is confused about, and I have a feeling that if the original fix is still relevant, the problem the original fix wanted to address will resurface as a regression. If I am reading the patch correctly, Dscho's is to avoid [*] reusing a slot while any run_active_slot() is still waiting for its completion. The approach would solve the problem the original fix wanted to solve in a different way. Personally I do not think such a surgery is necessary only to squelch false positives from a new warning compiler, though. [Footnote] * I said "is to avoid", not "avoids", because I haven't studied the patch with sufficient degree of carefulness to say for sure, even though I can see that is the intent.
Hi Junio, On Tue, 24 May 2022, Junio C Hamano wrote: > The "clear slot->finished", by the way, is what I think is the right > thing to do, especially that the objective is to squelch the false > positive warning from a new compiler. If there is a way to annotate > the line for the compiler to tell it not to warn about it, that would > have been even better. We could do something like this: -- snip -- diff --git a/http.c b/http.c index b08795715f8a..2ac8d51d3668 100644 --- a/http.c +++ b/http.c @@ -1365,7 +1365,14 @@ void run_active_slot(struct active_request_slot *slot) struct timeval select_timeout; int finished = 0; +#if __GNUC__ >= 12 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-pointer" +#endif slot->finished = &finished; +#if __GNUC__ >= 12 +#pragma GCC diagnostic pop +#endif while (!finished) { step_active_slots(); -- snap -- That's quite ugly, though. And what's worse, it is pretty unreadable, too. Ciao, Dscho
On Tue, May 24 2022, Johannes Schindelin wrote: > Hi Junio, > > On Tue, 24 May 2022, Junio C Hamano wrote: > >> The "clear slot->finished", by the way, is what I think is the right >> thing to do, especially that the objective is to squelch the false >> positive warning from a new compiler. If there is a way to annotate >> the line for the compiler to tell it not to warn about it, that would >> have been even better. > > We could do something like this: > > -- snip -- > diff --git a/http.c b/http.c > index b08795715f8a..2ac8d51d3668 100644 > --- a/http.c > +++ b/http.c > @@ -1365,7 +1365,14 @@ void run_active_slot(struct active_request_slot *slot) > struct timeval select_timeout; > int finished = 0; > > +#if __GNUC__ >= 12 > +#pragma GCC diagnostic push > +#pragma GCC diagnostic ignored "-Wdangling-pointer" > +#endif > slot->finished = &finished; > +#if __GNUC__ >= 12 > +#pragma GCC diagnostic pop > +#endif > while (!finished) { > step_active_slots(); > -- snap -- > > That's quite ugly, though. And what's worse, it is pretty unreadable, too. Unfortunately that sort of thing is a logic error as clang, ICC and probably others are on a mission to make __GNUC__ as useless as possible: https://stackoverflow.com/questions/38499462/how-to-tell-clang-to-stop-pretending-to-be-other-compilers I think it *might* work in practice though, my local clang claims to be gcc 4, so maybe everyone faking it stops at a low enough version? But did you spot 9c539d1027d (config.mak.dev: alternative workaround to gcc 12 warning in http.c, 2022-04-15)? We already disable this file-wide in config.mak.dev, but I didn't check if the Windows code was using that (or if you were targeting those without DEVELOPER=1). We could move that to thake main Makefile, but then we'd have to call detect-compiler there. I have some local patches to do something like that if there's interest (rather, to bootstrap compilation by compiling a C object and getting the macro values, instead of relying on that shellscript).
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > Hi Junio, > > On Tue, 24 May 2022, Junio C Hamano wrote: > >> The "clear slot->finished", by the way, is what I think is the right >> thing to do, especially that the objective is to squelch the false >> positive warning from a new compiler. If there is a way to annotate >> the line for the compiler to tell it not to warn about it, that would >> have been even better. > > We could do something like this: Yuck. > -- snip -- > diff --git a/http.c b/http.c > index b08795715f8a..2ac8d51d3668 100644 > --- a/http.c > +++ b/http.c > @@ -1365,7 +1365,14 @@ void run_active_slot(struct active_request_slot *slot) > struct timeval select_timeout; > int finished = 0; > > +#if __GNUC__ >= 12 > +#pragma GCC diagnostic push > +#pragma GCC diagnostic ignored "-Wdangling-pointer" > +#endif > slot->finished = &finished; > +#if __GNUC__ >= 12 > +#pragma GCC diagnostic pop > +#endif > while (!finished) { > step_active_slots(); > -- snap -- > > That's quite ugly, though. And what's worse, it is pretty unreadable, too. Yes, very ugly. Would an unconditional slot->finished = NULL; at the end squelch the warning? Or there is a way to say "we make all warnings into errors with -Werror, but we do not want to turn this dangling-pointer warning to an error, because it has false positives"? Or we could add "-Wno-dangling-pointer" globally, perhaps.
Hi Junio, On Tue, 24 May 2022, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: > > > On Tue, 24 May 2022, Junio C Hamano wrote: > > > >> The "clear slot->finished", by the way, is what I think is the right > >> thing to do, especially that the objective is to squelch the false > >> positive warning from a new compiler. If there is a way to annotate > >> the line for the compiler to tell it not to warn about it, that would > >> have been even better. > > > > We could do something like this: > > Yuck. > > > -- snip -- > > diff --git a/http.c b/http.c > > index b08795715f8a..2ac8d51d3668 100644 > > --- a/http.c > > +++ b/http.c > > @@ -1365,7 +1365,14 @@ void run_active_slot(struct active_request_slot *slot) > > struct timeval select_timeout; > > int finished = 0; > > > > +#if __GNUC__ >= 12 > > +#pragma GCC diagnostic push > > +#pragma GCC diagnostic ignored "-Wdangling-pointer" > > +#endif > > slot->finished = &finished; > > +#if __GNUC__ >= 12 > > +#pragma GCC diagnostic pop > > +#endif > > while (!finished) { > > step_active_slots(); > > -- snap -- > > > > That's quite ugly, though. And what's worse, it is pretty unreadable, too. > > Yes, very ugly. Would an unconditional > > slot->finished = NULL; > > at the end squelch the warning? No, unfortunately not: https://github.com/dscho/git/actions/runs/2383492484 As you mentioned elsewhere, the error is clearly about the assignment in the first place, and it does not matter that the function will rectify the situation. It's the correct thing to do for the compiler, too: since `slot->finished` already has the pointer, and since the `active_request_slot` struct is declared globally, code outside the current file might squirrel that pointer away for later use. > Or there is a way to say "we make all warnings into errors with > -Werror, but we do not want to turn this dangling-pointer warning to > an error, because it has false positives"? > > Or we could add "-Wno-dangling-pointer" globally, perhaps. I'd like to avoid that because it would quite likely hide legitimate issues elsewhere. It currently seems to be the easiest solution to simply turn the local variable into a heap variable: -- snip -- diff --git a/http.c b/http.c index f92859f43fa..0712debd558 100644 --- a/http.c +++ b/http.c @@ -1327,10 +1327,10 @@ void run_active_slot(struct active_request_slot *slot) fd_set excfds; int max_fd; struct timeval select_timeout; - int finished = 0; + int *finished = xcalloc(1, sizeof(int)); - slot->finished = &finished; - while (!finished) { + slot->finished = finished; + while (!*finished) { step_active_slots(); if (slot->in_use) { @@ -1367,6 +1367,9 @@ void run_active_slot(struct active_request_slot *slot) select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); } } + if (slot->finished == finished) + slot->finished = NULL; + free(finished); } static void release_active_slot(struct active_request_slot *slot) -- snap -- This pacifies GCC (https://github.com/dscho/git/runs/6589617700) and is the most minimally-intrusive work-around of which I am currently aware. Ciao, Dscho
On Wed, May 25 2022, Johannes Schindelin wrote: > Hi Junio, > > On Tue, 24 May 2022, Junio C Hamano wrote: > >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes: >> >> > On Tue, 24 May 2022, Junio C Hamano wrote: >> > >> >> The "clear slot->finished", by the way, is what I think is the right >> >> thing to do, especially that the objective is to squelch the false >> >> positive warning from a new compiler. If there is a way to annotate >> >> the line for the compiler to tell it not to warn about it, that would >> >> have been even better. >> > >> > We could do something like this: >> >> Yuck. >> >> > -- snip -- >> > diff --git a/http.c b/http.c >> > index b08795715f8a..2ac8d51d3668 100644 >> > --- a/http.c >> > +++ b/http.c >> > @@ -1365,7 +1365,14 @@ void run_active_slot(struct active_request_slot *slot) >> > struct timeval select_timeout; >> > int finished = 0; >> > >> > +#if __GNUC__ >= 12 >> > +#pragma GCC diagnostic push >> > +#pragma GCC diagnostic ignored "-Wdangling-pointer" >> > +#endif >> > slot->finished = &finished; >> > +#if __GNUC__ >= 12 >> > +#pragma GCC diagnostic pop >> > +#endif >> > while (!finished) { >> > step_active_slots(); >> > -- snap -- >> > >> > That's quite ugly, though. And what's worse, it is pretty unreadable, too. >> >> Yes, very ugly. Would an unconditional >> >> slot->finished = NULL; >> >> at the end squelch the warning? > > No, unfortunately not: > https://github.com/dscho/git/actions/runs/2383492484 Yes it does. Didn't you just have a PBCAK between writing that test & pushing it? Your https://github.com/dscho/git/blob/tmp/http.c#L1370-L1371 shows that you didn't make that edit. This on top of "seen" makes the warning go away: - if (slot->finished == &finished) - slot->finished = NULL; + slot->finished = NULL; This is also all covered in the initial thread from back in January, which if you're slowly re-discovering the learnings from there I encourage you to read in more detail... :) > As you mentioned elsewhere, the error is clearly about the assignment in > the first place, and it does not matter that the function will rectify the > situation. It's the correct thing to do for the compiler, too: since > `slot->finished` already has the pointer, and since the > `active_request_slot` struct is declared globally, code outside the > current file might squirrel that pointer away for later use. Per the above this isn't true, and in some side-thread replies (and in the initial thread) I've linked to the GCC code in question. NULL-ing the slot is sufficient, it doesn't matter that the struct it's in survives the function, just that the pointer isn't exposed. >> Or there is a way to say "we make all warnings into errors with >> -Werror, but we do not want to turn this dangling-pointer warning to >> an error, because it has false positives"? >> >> Or we could add "-Wno-dangling-pointer" globally, perhaps. > > I'd like to avoid that because it would quite likely hide legitimate > issues elsewhere. > > It currently seems to be the easiest solution to simply turn the local > variable into a heap variable: > > -- snip -- > diff --git a/http.c b/http.c > index f92859f43fa..0712debd558 100644 > --- a/http.c > +++ b/http.c > @@ -1327,10 +1327,10 @@ void run_active_slot(struct active_request_slot *slot) > fd_set excfds; > int max_fd; > struct timeval select_timeout; > - int finished = 0; > + int *finished = xcalloc(1, sizeof(int)); > > - slot->finished = &finished; > - while (!finished) { > + slot->finished = finished; > + while (!*finished) { > step_active_slots(); > > if (slot->in_use) { > @@ -1367,6 +1367,9 @@ void run_active_slot(struct active_request_slot *slot) > select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); > } > } > + if (slot->finished == finished) > + slot->finished = NULL; > + free(finished); > } Also, if we were going to tweak this extensively I'd think this slightly larger POC patch would be a better direction, i.e. we don't need a pointer at all, we're just (ab)using it for a tri-state NULL/0/1, why not just use an enum? I think the "if it's what we just set it to" is just cargo-culting, is there anything to show that run_active_slot() is reentrant? Wouldn't we be better off with a static variable + BUG() that we increment/decremant and panic if it's anything but 0 and 1 if we'd like to add paranoia around that? diff --git a/http-walker.c b/http-walker.c index b8f0f98ae14..26184a82ddb 100644 --- a/http-walker.c +++ b/http-walker.c @@ -225,13 +225,13 @@ static void process_alternates_response(void *callback_data) alt_req->url->buf); active_requests++; slot->in_use = 1; - if (slot->finished) - (*slot->finished) = 0; + if (slot->f != FIN_UNSET) + slot->f = FIN_NO; if (!start_active_slot(slot)) { cdata->got_alternates = -1; slot->in_use = 0; - if (slot->finished) - (*slot->finished) = 1; + if (slot->f != FIN_UNSET) + slot->f = FIN_YES; } return; } diff --git a/http.c b/http.c index b148468b267..845dd40768c 100644 --- a/http.c +++ b/http.c @@ -197,8 +197,8 @@ static void finish_active_slot(struct active_request_slot *slot) closedown_active_slot(slot); curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); - if (slot->finished) - (*slot->finished) = 1; + if (slot->f != FIN_UNSET) + slot->f = FIN_YES; /* Store slot results so they can be read after the slot is reused */ if (slot->results) { @@ -1204,7 +1204,7 @@ struct active_request_slot *get_active_slot(void) active_requests++; slot->in_use = 1; slot->results = NULL; - slot->finished = NULL; + slot->f = FIN_UNSET; slot->callback_data = NULL; slot->callback_func = NULL; curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file); @@ -1327,10 +1327,9 @@ void run_active_slot(struct active_request_slot *slot) fd_set excfds; int max_fd; struct timeval select_timeout; - int finished = 0; - slot->finished = &finished; - while (!finished) { + slot->f = FIN_NO; + while (slot->f == FIN_NO) { step_active_slots(); if (slot->in_use) { diff --git a/http.h b/http.h index df1590e53a4..fc664d90bc9 100644 --- a/http.h +++ b/http.h @@ -19,12 +19,13 @@ struct slot_results { long http_connectcode; }; +enum fin { FIN_UNSET, FIN_NO, FIN_YES }; struct active_request_slot { CURL *curl; int in_use; CURLcode curl_result; long http_code; - int *finished; + enum fin f; struct slot_results *results; void *callback_data; void (*callback_func)(void *data);
diff --git a/http-walker.c b/http-walker.c index 910fae539b8..5cc369dea85 100644 --- a/http-walker.c +++ b/http-walker.c @@ -225,13 +225,9 @@ static void process_alternates_response(void *callback_data) alt_req->url->buf); active_requests++; slot->in_use = 1; - if (slot->finished != NULL) - (*slot->finished) = 0; if (!start_active_slot(slot)) { cdata->got_alternates = -1; slot->in_use = 0; - if (slot->finished != NULL) - (*slot->finished) = 1; } return; } diff --git a/http.c b/http.c index f92859f43fa..00206676597 100644 --- a/http.c +++ b/http.c @@ -197,8 +197,7 @@ static void finish_active_slot(struct active_request_slot *slot) closedown_active_slot(slot); curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); - if (slot->finished != NULL) - (*slot->finished) = 1; + slot->in_use = 0; /* Store slot results so they can be read after the slot is reused */ if (slot->results != NULL) { @@ -1176,13 +1175,14 @@ struct active_request_slot *get_active_slot(void) process_curl_messages(); } - while (slot != NULL && slot->in_use) + while (slot != NULL && (slot->in_use || slot->reserved_for_use)) slot = slot->next; if (slot == NULL) { newslot = xmalloc(sizeof(*newslot)); newslot->curl = NULL; newslot->in_use = 0; + newslot->reserved_for_use = 0; newslot->next = NULL; slot = active_queue_head; @@ -1204,7 +1204,6 @@ struct active_request_slot *get_active_slot(void) active_requests++; slot->in_use = 1; slot->results = NULL; - slot->finished = NULL; slot->callback_data = NULL; slot->callback_func = NULL; curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file); @@ -1296,7 +1295,7 @@ void fill_active_slots(void) } while (slot != NULL) { - if (!slot->in_use && slot->curl != NULL + if (!slot->in_use && !slot->reserved_for_use && slot->curl && curl_session_count > min_curl_sessions) { curl_easy_cleanup(slot->curl); slot->curl = NULL; @@ -1327,10 +1326,9 @@ void run_active_slot(struct active_request_slot *slot) fd_set excfds; int max_fd; struct timeval select_timeout; - int finished = 0; - slot->finished = &finished; - while (!finished) { + slot->reserved_for_use = 1; + while (slot->in_use) { step_active_slots(); if (slot->in_use) { @@ -1367,6 +1365,7 @@ void run_active_slot(struct active_request_slot *slot) select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); } } + slot->reserved_for_use = 0; } static void release_active_slot(struct active_request_slot *slot) diff --git a/http.h b/http.h index df1590e53a4..3b2f6da570c 100644 --- a/http.h +++ b/http.h @@ -22,9 +22,9 @@ struct slot_results { struct active_request_slot { CURL *curl; int in_use; + int reserved_for_use; CURLcode curl_result; long http_code; - int *finished; struct slot_results *results; void *callback_data; void (*callback_func)(void *data);