Skip to content

net/http: fix nil didTimeout deref when a client dial fails - #68

Merged
deadprogram merged 1 commit into
tinygo-org:mainfrom
0magnet:fix-didtimeout-nil-deref
Aug 28, 2026
Merged

net/http: fix nil didTimeout deref when a client dial fails#68
deadprogram merged 1 commit into
tinygo-org:mainfrom
0magnet:fix-didtimeout-nil-deref

Conversation

@0pcom

@0pcom 0pcom commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

A failed dial panics instead of returning the error.

send() returns the named didTimeout on its error paths, but TinyGo dropped setRequestCancel, so nothing ever assigns it — it is a nil func() bool. Client.do then calls it on exactly that path:

if !deadline.IsZero() && didTimeout() {   // client.go:465

so any client request whose dial fails with a deadline set dereferences a nil func value. The error the user should have seen never surfaces.

alwaysFalse already exists in this file (line 386) for precisely this shape, so the fix is to return it rather than the never-assigned named return. Same on the "nil *Response with a nil error" path just below, which had the same problem.

Found while running gRPC over TinyGo, where a refused connection paniced rather than reporting a dial error.

Comment thread http/transport.go Outdated
// TINYGO: stored only. The fetch-based round tripper performs its own TLS
// handshaking (the browser does it), so this bound is not separately
// enforced — the field exists so std net/http client code that sets it
// (e.g. skywire's in-tab skysocks client) compiles unchanged.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please do not mention 3rd party solutions when not relevant to the implementation

@0pcom

0pcom commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Fixed — the comment now says the field exists so that client code setting it compiles unchanged, without naming anyone.

I also went looking for the same thing elsewhere and found one more, on the Proxy field in #70, which named a downstream project for the same reason. That one is rewritten too, so you should not have to make the point twice.

@deadprogram

Copy link
Copy Markdown
Member

@b0ch3nski any more feedback on this PR?

@deadprogram

Copy link
Copy Markdown
Member

@0pcom can you please rebase this PR against the latest main. Thanks.

@0pcom
0pcom force-pushed the fix-didtimeout-nil-deref branch from 42a16f1 to 4079329 Compare August 24, 2026 16:49
@0pcom

0pcom commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on latest main.

@deadprogram

Copy link
Copy Markdown
Member

@0pcom I think this PR should really only have 1 commit 02f75fa

Client.do calls didTimeout() on the error path (line 461), and the contract is
that send() returns a non-nil didTimeout whenever err != nil. TinyGo dropped
setRequestCancel but left the roundTrip error path returning the nil named
return value, so any http.Client{Timeout: ...} request whose dial failed (e.g.
connection refused) panicked with a nil func-value dereference instead of
returning the error. Return alwaysFalse on those error paths, matching the
other error returns in send().

Verified: http.Client{Timeout}.Get to a refused port now returns
"connection refused" instead of panicking.
@0pcom
0pcom force-pushed the fix-didtimeout-nil-deref branch from 4079329 to 9085777 Compare August 27, 2026 19:01
@0pcom

0pcom commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Down to the one commit, rebased on current main.

The other two added Transport.TLSHandshakeTimeout, which landed separately in 1638a87, so they were redundant as well as extra. What is left is just the didTimeout fix.

@deadprogram

Copy link
Copy Markdown
Member

Thanks @0pcom now merging.

@deadprogram
deadprogram merged commit 70037cf into tinygo-org:main Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants