Skip to content

gai_strerror() is not thread-safe on Windows #15568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 8, 2024
Merged

Conversation

cmb69
Copy link
Member

@cmb69 cmb69 commented Aug 24, 2024

This PR is mainly about avoiding gai_strerror() on Windows, because the function is not thread-safe there[1].

However, it also fixes the IPv6 configuration on Windows where HAVE_GAI_STRERROR only was defined if IPv6 support is requested (the default; can be disabled with --disable-ipv6), although that function is generally available. For BC, we define HAVE_GAI_STRERROR but do no longer use it internally. If extensions use it, they should be fixed (if necessary), but we don't want to break them that late in the pre-release cycle of PHP 8.4.

Note that I'm fine with dropping the changes to config.w32, but the 5th commit should be merged (maybe in a different form; code is not nice as is).

[1] https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-gai_strerrora


WSPiApi.h has been created in 2000, so we can safely assume that it is available everywhere nowadays. Furthermore, gai_strerror() is available regardless of whether there is IPv6 support.


This came up in #15567, and solves the easy part. Not using gai_strerror() on Windows, because it is not thread-safe would be as simple as define PHP_GAI_STRERROR(x) (php_win32_error_to_msg(x))if there wasn't a memory leak because the returned buffer needs to be freed by the caller. Any suggestions on how to solve this in a clean way are welcome!

Verified

This commit was signed with the committer’s verified signature. The key has expired.
cmb69 Christoph M. Becker
WSPiApi.h has been created in 2000, so we can safely assume that it is
available everywhere nowadays.  Furthermore, `gai_strerror()` is
available regardless of whether there is IPv6 support.
@NattyNarwhal
Copy link
Member

FWIW, I brought up in GH-15555 about using getaddrinfo instead of gethostbyname about if we're basically assuming IPv6 by using the modern functionality with sketchy attempts to test for it, and if it might be better to assume v6 presence/not have the build option for it.

Verified

This commit was signed with the committer’s verified signature. The key has expired.
cmb69 Christoph M. Becker
@cmb69
Copy link
Member Author

cmb69 commented Aug 24, 2024

Making IPv6 mandatory seems like a good idea, and would render this patch moot (if we require IPv6 for PHP 8.4, what might be a bit late), but the main point of this PR is to avoid calling gai_strerror() on Windows, because it is documented to be not thread-safe (although I haven't tackled that so far; even screwed up the easy part with the first commit).

@NattyNarwhal
Copy link
Member

Yeah, it's probably too late to get any v6 changes in for 8.4, but refactors that get us further there are still a good idea.

Refactor

Verified

This commit was signed with the committer’s verified signature. The key has expired.
cmb69 Christoph M. Becker
We extract `report_getaddrinfo_failure()`, and refactor that further.
While this code is now a tad bit slower, that shouldn't matter since it
is error handling.

We also cheat a bit, since adding a proper format specifier for
`php_error_docref()` is not a proper refactoring, but more like a bug
fix.
@cmb69 cmb69 requested a review from bukka as a code owner September 1, 2024 17:03
main/network.c Outdated
} else {
php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo for %s failed: %s", host, PHP_GAI_STRERROR(n));
}
report_getaddrinfo_failure(host, n, error_string);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code in the } else if (res == NULL) { below could also call report_getaddrinfo_failure(), but the two legs have slightly different error messages: one shows errno, but not the other. I doubt that showing errno here is correct (since getaddrinfo() has apparently not failed, but I'm not sure. I'm not even sure if that code would ever be executed; isn't res supposed to be set if getaddrinfo() returns 0?

Verified

This commit was signed with the committer’s verified signature. The key has expired.
cmb69 Christoph M. Becker
This reverts commit 7b151af2103216295ed82e87d38dae3663ddc35a.

Verified

This commit was signed with the committer’s verified signature. The key has expired.
cmb69 Christoph M. Becker
First we refactor to have only a single usage of `PHP_GAI_STRERROR()`
left; then we drop the macro in favor of calling the different
functions conditionally in an ad-hoc style.

This is necessary because the return value of `php_win32_error_to_msg`
needs to be freed by the caller.

The error messages are no more inline with other error messages, since
`gai_strerror()` apparently always appends a period and a space.
@cmb69 cmb69 changed the title Properly configure IPv4/v6 on Windows gai_strerror() is not thread-safe on Windows Sep 1, 2024
@cmb69 cmb69 merged commit edcd6cc into php:master Sep 8, 2024
10 checks passed
@cmb69 cmb69 deleted the cmb/ipv4v6 branch September 8, 2024 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants