TcpSocket::connect is now the one error path in morph::net whose renderer
has not been shown to be safe on the threads this subsystem runs. #625 replaced
the seven std::strerror calls in include/morph/net/detail/tcp_socket.hpp
with std::system_category().message(); it deliberately did not touch
::gai_strerror, and this issue records the residue rather than letting the
decision disappear into that pull request.
The site (include/morph/net/detail/tcp_socket.hpp:112 after #625, :111
before it):
throw std::runtime_error("TcpSocket::connect: getaddrinfo failed for " + host + ": " + ::gai_strerror(rc));
Why it was not folded into #625
There is no drop-in replacement. rc is an EAI_* code from ::getaddrinfo,
not an errno value, so std::system_category().message(rc) would render a
confidently wrong string (EAI_NONAME is -2 on glibc; system_category()
would describe errno -2). Any repair here needs its own design decision — a
hand-written EAI_* table, or an argument that the call is already safe — and
that is a different change from swapping one renderer for another.
Verification status
Not reproduced, and not resolved either way. What was actually measured, on
a8511aa6 with clang-tidy 22.1.8:
-
clang-tidy's concurrency-mt-unsafe does not classify ::gai_strerror as
unsafe, while it classifies std::strerror in the same translation unit as
unsafe. Probe file and output:
#include <netdb.h>
#include <cstring>
#include <string>
std::string f(int e) { return ::gai_strerror(e); }
std::string g(int e) { return std::strerror(e); }
$ clang-tidy --checks='-*,concurrency-mt-unsafe' net625_gai.cpp -- -std=c++23
1 warning generated.
net625_gai.cpp:5:31: warning: function is not thread safe [concurrency-mt-unsafe]
5 | std::string g(int e) { return std::strerror(e); }
| ^
-
The same check over the whole header reports nothing at the ::gai_strerror
line — the six findings it does report on a8511aa6 are all std::strerror
sites:
$ clang-tidy -p build/net --checks='-*,concurrency-mt-unsafe' \
--header-filter='include/morph/.*' tests/net/test_tcp_socket.cpp
include/morph/net/detail/tcp_socket.hpp:195:92: error: function is not thread safe [concurrency-mt-unsafe,-warnings-as-errors]
include/morph/net/detail/tcp_socket.hpp:206:90: error: function is not thread safe [concurrency-mt-unsafe,-warnings-as-errors]
include/morph/net/detail/tcp_socket.hpp:211:92: error: function is not thread safe [concurrency-mt-unsafe,-warnings-as-errors]
include/morph/net/detail/tcp_socket.hpp:276:75: error: function is not thread safe [concurrency-mt-unsafe,-warnings-as-errors]
include/morph/net/detail/tcp_socket.hpp:353:81: error: function is not thread safe [concurrency-mt-unsafe,-warnings-as-errors]
include/morph/net/detail/tcp_socket.hpp:371:80: error: function is not thread safe [concurrency-mt-unsafe,-warnings-as-errors]
What was NOT verified, and is the substance of this issue:
- Whether POSIX requires
gai_strerror to be thread-safe. Not checked against
the standard text; man 3 gai_strerror is not installed on the machine this
was measured on, so its ATTRIBUTES table was not read either.
- Whether glibc's implementation is in fact MT-Safe. Inferred-only, from
clang-tidy's classification, which is a tool's opinion about a function name
and not a reading of the implementation.
- Whether
TcpSocket::connect is reachable from more than one thread at a
time. It is called from SocketBackend's I/O thread
(socket_backend.hpp:909) and directly from test threads; whether two
connect calls can overlap in a real deployment was not established.
So the honest state is: a renderer whose thread-safety this project has
asserted nowhere, sitting on an error path in a subsystem that owns several
threads. That is smaller than #625 was, and it is not nothing.
What would change the verdict
- Close as
invalid if POSIX requires gai_strerror to be thread-safe, or
if the platforms this transport supports (Linux/macOS — the header is POSIX
only) all document it MT-Safe. Cite the text, not a tool's check list.
- Close as fixed if the call is replaced with something whose guarantee is
written down — most plausibly an explicit EAI_* switch, since
std::system_category() cannot describe these codes.
- Keep open, and raise it, if it turns out
connect() can run concurrently
with itself on a supported platform where the function is not MT-Safe.
Found while implementing #625. Filed rather than folded, per AGENTS.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VptDWG2fKr2vBnLSJcgzgW
TcpSocket::connectis now the one error path inmorph::netwhose rendererhas not been shown to be safe on the threads this subsystem runs. #625 replaced
the seven
std::strerrorcalls ininclude/morph/net/detail/tcp_socket.hppwith
std::system_category().message(); it deliberately did not touch::gai_strerror, and this issue records the residue rather than letting thedecision disappear into that pull request.
The site (
include/morph/net/detail/tcp_socket.hpp:112after #625,:111before it):
Why it was not folded into #625
There is no drop-in replacement.
rcis anEAI_*code from::getaddrinfo,not an
errnovalue, sostd::system_category().message(rc)would render aconfidently wrong string (
EAI_NONAMEis-2on glibc;system_category()would describe errno
-2). Any repair here needs its own design decision — ahand-written
EAI_*table, or an argument that the call is already safe — andthat is a different change from swapping one renderer for another.
Verification status
Not reproduced, and not resolved either way. What was actually measured, on
a8511aa6with clang-tidy 22.1.8:clang-tidy's
concurrency-mt-unsafedoes not classify::gai_strerrorasunsafe, while it classifies
std::strerrorin the same translation unit asunsafe. Probe file and output:
The same check over the whole header reports nothing at the
::gai_strerrorline — the six findings it does report on
a8511aa6are allstd::strerrorsites:
What was NOT verified, and is the substance of this issue:
gai_strerrorto be thread-safe. Not checked againstthe standard text;
man 3 gai_strerroris not installed on the machine thiswas measured on, so its ATTRIBUTES table was not read either.
clang-tidy's classification, which is a tool's opinion about a function name
and not a reading of the implementation.
TcpSocket::connectis reachable from more than one thread at atime. It is called from
SocketBackend's I/O thread(
socket_backend.hpp:909) and directly from test threads; whether twoconnectcalls can overlap in a real deployment was not established.So the honest state is: a renderer whose thread-safety this project has
asserted nowhere, sitting on an error path in a subsystem that owns several
threads. That is smaller than #625 was, and it is not nothing.
What would change the verdict
invalidif POSIX requiresgai_strerrorto be thread-safe, orif the platforms this transport supports (Linux/macOS — the header is POSIX
only) all document it MT-Safe. Cite the text, not a tool's check list.
written down — most plausibly an explicit
EAI_*switch, sincestd::system_category()cannot describe these codes.connect()can run concurrentlywith itself on a supported platform where the function is not MT-Safe.
Found while implementing #625. Filed rather than folded, per AGENTS.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VptDWG2fKr2vBnLSJcgzgW