[PATCH v2] http API: fix dangling pointer issue noted by GCC 12.0
From: Ævar Arnfjörð Bjarmason <hidden>
Date: 2022-02-25 09:09:21
Subsystem:
the rest · Maintainer:
Linus Torvalds
The pre-release GCC 12.0 development branch has a new warning about
dangling pointers in -Wall:
http.c: In function ‘run_active_slot’:
http.c:1332:24: error: storing the address of local variable ‘finished’ in ‘*slot.finished’ [-Werror=dangling-pointer=]
1332 | slot->finished = &finished;
| ~~~~~~~~~~~~~~~^~~~~~~~~~~
http.c:1330:13: note: ‘finished’ declared here
1330 | int finished = 0;
| ^~~~~~~~
This is on a locally built "gcc (GCC) 12.0.1 20220120 (experimental)",
built from gcc.git's 8bc700f4c3f (Enhance vec_pack_trunc for integral
mode mask., 2022-01-17).
The GCC warning is specifically about pointers that survive the exit
of the function. See a comment added to
"pass_waccess::use_after_inval_p" in the GCC commit that added the
warning, or:
/* The use is one of a dangling pointer if a clobber of the variable
[the pointer points to] has not been found before the function exit
point. */
[...]
There's a few possible ways to fix this, but the simplest is to assign
NULL to "slot->finished" at the end of run_active_slot(), it's the
only caller that ever assigns non-NULL to it. It was suggested[2] to
guard that with "if (slot->finished == &finished)", but that'll still
trigger the warning.
1. https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=9d6a0f388eb048f8d87f47af78f07b5ce513bfe6
2. https://lore.kernel.org/git/xmqq8rv2nggn.fsf@gitster.g/ (local)
Signed-off-by: Ævar Arnfjörð Bjarmason <redacted>
---
A much simpler fix for a warning new in the GCC v12 pre-release.
Range-diff against v1:
1: 1cec367e805 ! 1: 777838267a5 http API: fix dangling pointer issue noted by GCC 12.0
@@ Commit message
built from gcc.git's 8bc700f4c3f (Enhance vec_pack_trunc for integral
mode mask., 2022-01-17).
- To fix this I first simply made the member "int finished",
- i.e. removing the pointer indirection. It turns out that nothing cared
- about the state of it being a NULL pointer v.s. "*ptr == 0".
+ The GCC warning is specifically about pointers that survive the exit
+ of the function. See a comment added to
+ "pass_waccess::use_after_inval_p" in the GCC commit that added the
+ warning, or:
- But we can instead amend the code added in baa7b67d091 (HTTP slot
- reuse fixes, 2006-03-10) to get rid of "int *finished" entirely. I
- instrumented the code to add this after every use of slot->finished or
- slot->in_use:
+ /* The use is one of a dangling pointer if a clobber of the variable
+ [the pointer points to] has not been found before the function exit
+ point. */
+ [...]
- if (slot->finished && slot->in_use == *slot->finished) BUG("in-use = %d and finished = %d disconnect", slot->in_use, *slot->finished);
- if (!slot->finished && !slot->in_use) BUG("have !in-use and no finished pointer");
+ There's a few possible ways to fix this, but the simplest is to assign
+ NULL to "slot->finished" at the end of run_active_slot(), it's the
+ only caller that ever assigns non-NULL to it. It was suggested[2] to
+ guard that with "if (slot->finished == &finished)", but that'll still
+ trigger the warning.
- Which never fires, but we would get occurrences of:
-
- if (!slot->finished && slot->in_use) BUG("have in-use and no finished pointer");
-
- I.e. we can simply drop the field and rely on "slot->in_use" in cases
- where we used "finished" before. The two fields were mirror images of
- each other, and the tri-state nature of "finished" wasn't something we
- relied upon.
+ 1. https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=9d6a0f388eb048f8d87f47af78f07b5ce513bfe6
+ 2. https://lore.kernel.org/git/xmqq8rv2nggn.fsf@gitster.g/ (local)
Signed-off-by: Ævar Arnfjörð Bjarmason [off-list ref]
- ## http-walker.c ##
-@@ http-walker.c: 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;
- }
-
## http.c ##
-@@ http.c: 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;
--
- /* Store slot results so they can be read after the slot is reused */
- if (slot->results != NULL) {
- slot->results->curl_result = slot->curl_result;
-@@ http.c: 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);
@@ http.c: 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) {
-+ while (slot->in_use) {
- step_active_slots();
+ select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
+ }
+ }
++ slot->finished = NULL;
+ }
- if (slot->in_use) {
-
- ## http.h ##
-@@ http.h: struct active_request_slot {
- int in_use;
- CURLcode curl_result;
- long http_code;
-- int *finished;
- struct slot_results *results;
- void *callback_data;
- void (*callback_func)(void *data);
+ static void release_active_slot(struct active_request_slot *slot)
http.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/http.c b/http.c
index 229da4d1488..2f67fbb33cd 100644
--- a/http.c
+++ b/http.c@@ -1367,6 +1367,7 @@ void run_active_slot(struct active_request_slot *slot) select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); } } + slot->finished = NULL; } static void release_active_slot(struct active_request_slot *slot)
--
2.35.1.1175.gf9e1b23ea35