Skip to content

net.openssl: fix double-free on shutdown()#27482

Open
davidebeatrici wants to merge 1 commit into
vlang:masterfrom
davidebeatrici:net-openssl-shutdown-crash-fix
Open

net.openssl: fix double-free on shutdown()#27482
davidebeatrici wants to merge 1 commit into
vlang:masterfrom
davidebeatrici:net-openssl-shutdown-crash-fix

Conversation

@davidebeatrici

Copy link
Copy Markdown
Contributor

The issue can be reliably reproduced by configuring a SOCKS5 proxy server, as follows:

#0  X509_VERIFY_PARAM_free (param=0xfeff) at ../crypto/x509/x509_vpm.c:100
#1  0x00007ffff7da37fc in SSL_CTX_free (a=0x555555626a00) at ../ssl/ssl_lib.c:4405
#2  0x00007ffff7da4aed in SSL_free (s=0x55555562dfb0) at ../ssl/ssl_lib.c:1446
#3  0x000055555558b144 in net__openssl__SSLConn_shutdown ()
#4  0x00005555555966b1 in net__http__HttpProxy_http_do ()
#5  0x0000555555598b08 in net__http__Request_method_and_url_to_response ()
#6  0x0000555555594b06 in net__http__Request_do ()
#7  0x00005555555947e4 in net.http.fetch ()
#8  0x000055555559bfb9 in main.main ()
#9  0x000055555559c997 in main ()
import net.http
import rand
import time

proxy_user := rand.string(16)
proxy_pass := rand.string(16)
proxy_url := 'socks5://${proxy_user}:${proxy_pass}@127.0.0.1:9050'

mut config := http.FetchConfig{
	url: 'https://vlang.io'
	proxy: http.new_http_proxy(proxy_url) or { panic(err) }
}

mut resp := http.Response{}
for {
	resp = http.fetch(config) or {
		println('Failed to fetch data from the server!')
		return
	}

	if resp.status_code != 200 {
		println('Bad status code: ${resp.status_code}\n')
		time.sleep(time.second * 10)
		continue
	}

	break
}

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.

@davidebeatrici davidebeatrici force-pushed the net-openssl-shutdown-crash-fix branch 2 times, most recently from a515cc0 to e1bdc14 Compare June 17, 2026 20:17
The issue can be reliably reproduced by configuring a SOCKS5 proxy server, as follows.

import net.http
import rand
import time

proxy_user := rand.string(16)
proxy_pass := rand.string(16)
proxy_url := 'socks5://${proxy_user}:${proxy_pass}@127.0.0.1:9050'

mut config := http.FetchConfig{
	url: 'https://vlang.io'
	proxy: http.new_http_proxy(proxy_url) or { panic(err) }
}

mut resp := http.Response{}
for {
	resp = http.fetch(config) or {
		println('Failed to fetch data from the server!')
		return
	}

	if resp.status_code != 200 {
		println('Bad status code: ${resp.status_code}\n')
		time.sleep(time.second * 10)
		continue
	}

	break
}

Backtrace:

X509_VERIFY_PARAM_free (param=0xfeff) at ../crypto/x509/x509_vpm.c:100
0x00007ffff7da37fc in SSL_CTX_free (a=0x555555626a00) at ../ssl/ssl_lib.c:4405
0x00007ffff7da4aed in SSL_free (s=0x55555562dfb0) at ../ssl/ssl_lib.c:1446
0x000055555558b144 in net__openssl__SSLConn_shutdown ()
0x00005555555966b1 in net__http__HttpProxy_http_do ()
0x0000555555598b08 in net__http__Request_method_and_url_to_response ()
0x0000555555594b06 in net__http__Request_do ()
0x00005555555947e4 in net.http.fetch ()
0x000055555559bfb9 in main.main ()
0x000055555559c997 in main ()
@davidebeatrici davidebeatrici force-pushed the net-openssl-shutdown-crash-fix branch from e1bdc14 to 8800b76 Compare June 17, 2026 22:34
@davidebeatrici

Copy link
Copy Markdown
Contributor Author
================== C compilation error (from tcc): ==============
cc: /tmp/v_1001/tsession_7f764db54740_01KVBWXFPZRPC97MV98N95XSAJ/reflection_test.01KVBXWH914SVZXNB5NAT3HBJ4.tmp.c:13349: error: ')' expected (got "*")
=================================================================
Try passing `-g` when compiling, to see a .v file:line information, that correlates more with the C error.
(Alternatively, pass `-show-c-output`, to print the full C error message).
builder error: 
==================
C error found while compiling generated C code.
This can be caused by invalid C interop code, C compiler flags, or a V compiler bug.
If your code is pure V and this still happens, please report it using `v bug file.v`,
or goto https://github.com/vlang/v/issues/new/choose .
You can also use #help on Discord: https://discord.gg/vlang .
FAIL  [   1/3212] C:  4321.1 ms, R:     0.000 ms vlib/v/tests/reflection_test.v
>> compilation failed:
================== C compilation error (from tcc): ==============
cc: /tmp/v_1001/tsession_7f764db54740_01KVBWXFPZRPC97MV98N95XSAJ/reflection_test.01KVBXWH914SVZXNB5NAT3HBJ4.tmp.c:13349: error: ')' expected (got "*")
=================================================================
Try passing `-g` when compiling, to see a .v file:line information, that correlates more with the C error.
(Alternatively, pass `-show-c-output`, to print the full C error message).
builder error: 
==================
C error found while compiling generated C code.
This can be caused by invalid C interop code, C compiler flags, or a V compiler bug.
If your code is pure V and this still happens, please report it using `v bug file.v`,
or goto https://github.com/vlang/v/issues/new/choose .
You can also use #help on Discord: https://discord.gg/vlang .
To reproduce just failure 1 run:    '/home/runner/work/v/v/v' -W -silent '/home/runner/work/v/v/vlib/v/tests/reflection_test.v'
> Longest 3 by compilation time:
    1 |   1:19.700 | vlib/veb/tests/static_handler_test.v
    2 |    16.532s | vlib/orm/orm_generic_where_shadow_test.v
    3 |    12.041s | vlib/v/parser/v_parser_test.v
> Longest 3 by run time:
    1 |  12:40.623 | vlib/v/generics/new_generics_regression_test.v
    2 |   4:41.604 | vlib/v/gen/c/coutput_test.v
    3 |   4:19.717 | vlib/v/compiler_errors_test.v
> Longest 3 by total time:
    1 |  12:41.810 | vlib/v/generics/new_generics_regression_test.v
    2 |   4:42.416 | vlib/v/gen/c/coutput_test.v
    3 |   4:20.754 | vlib/v/compiler_errors_test.v
Summary for testing: vlib: 1 failed, 3038 passed, 173 skipped, 3212 total. Elapsed time: 1174451 ms, on 4 parallel jobs. Comptime: 2705709 ms. Runtime: 1979355 ms.

Is this caused by my changes?

@JalonSolov

Copy link
Copy Markdown
Collaborator

Very doubtful.

@JalonSolov

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8800b76d8a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +111 to 113
if res == 0 {
// Second SSL_shutdown() needed for full bidirectional shutdown.
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Wait on retryable SSL_shutdown(0) results

When the underlying socket is non-blocking, such as builds using -d net_nonblocking_sockets or callers that set the TCP fd non-blocking, OpenSSL can return 0 from SSL_shutdown() because the shutdown is still in progress and SSL_get_error() would report SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE. This unconditional continue skips the existing wait logic below, so shutdown can busy-spin until the fd happens to become ready or forever if it never does; handle res == 0 through ssl_error() and wait/retry instead of immediately looping.

Useful? React with 👍 / 👎.

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.

2 participants