From 229ed2972784e04129b9808229640aa581e8be70 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 26 Aug 2025 17:24:28 -0400 Subject: [PATCH] fix Sockets type stability issues fixes #59397 --- base/stream.jl | 2 +- stdlib/Sockets/src/PipeServer.jl | 2 +- stdlib/Sockets/src/Sockets.jl | 18 ++++++++--- stdlib/Sockets/src/addrinfo.jl | 4 +-- test/trimming/Makefile | 12 ++++++-- test/trimming/hello.jl | 35 ++------------------- test/trimming/trimmability.jl | 52 ++++++++++++++++++++++++++++++++ test/trimming/trimming.jl | 7 +++-- 8 files changed, 86 insertions(+), 46 deletions(-) create mode 100644 test/trimming/trimmability.jl diff --git a/base/stream.jl b/base/stream.jl index d9445ad6703df..40106436ebd05 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -373,7 +373,7 @@ end function isopen(x::Union{LibuvStream, LibuvServer}) if x.status == StatusUninit || x.status == StatusInit || x.handle === C_NULL - throw(ArgumentError("$x is not initialized")) + throw(ArgumentError("stream not initialized")) end return x.status != StatusClosed end diff --git a/stdlib/Sockets/src/PipeServer.jl b/stdlib/Sockets/src/PipeServer.jl index 0e9d76c52bef3..8eb1c0848d02b 100644 --- a/stdlib/Sockets/src/PipeServer.jl +++ b/stdlib/Sockets/src/PipeServer.jl @@ -103,7 +103,7 @@ function connect!(sock::PipeEndpoint, path::AbstractString) req = Libc.malloc(Base._sizeof_uv_connect) uv_req_set_data(req, C_NULL) ccall(:uv_pipe_connect, Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}), req, sock.handle, path, - @cfunction(uv_connectcb, Cvoid, (Ptr{Cvoid}, Cint))) + @cfunction(uv_connectcb_pipe, Cvoid, (Ptr{Cvoid}, Cint))) sock.status = StatusConnecting iolock_end() return sock diff --git a/stdlib/Sockets/src/Sockets.jl b/stdlib/Sockets/src/Sockets.jl index 58438b152d825..1ea9fa1febb7e 100644 --- a/stdlib/Sockets/src/Sockets.jl +++ b/stdlib/Sockets/src/Sockets.jl @@ -456,7 +456,7 @@ function send(sock::UDPSocket, ipaddr::IPAddr, port::Integer, msg) finally Base.sigatomic_end() iolock_begin() - q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) + q = ct.queue; q === nothing || Base.list_deletefirst!(q::Base.IntrusiveLinkedList{Task}, ct) if uv_req_data(uvw) != C_NULL # uvw is still alive, # so make sure we won't get spurious notifications later @@ -474,9 +474,19 @@ end #from `connect` -function uv_connectcb(conn::Ptr{Cvoid}, status::Cint) +function uv_connectcb_tcp(conn::Ptr{Cvoid}, status::Cint) hand = ccall(:jl_uv_connect_handle, Ptr{Cvoid}, (Ptr{Cvoid},), conn) - sock = @handle_as hand LibuvStream + sock = @handle_as hand TCPSocket + connectcb(conn, status, hand, sock) +end + +function uv_connectcb_pipe(conn::Ptr{Cvoid}, status::Cint) + hand = ccall(:jl_uv_connect_handle, Ptr{Cvoid}, (Ptr{Cvoid},), conn) + sock = @handle_as hand PipeEndpoint + connectcb(conn, status, hand, sock) +end + +function connectcb(conn::Ptr{Cvoid}, status::Cint, hand::Ptr{Cvoid}, sock::LibuvStream) lock(sock.cond) try if status >= 0 # success @@ -508,7 +518,7 @@ function connect!(sock::TCPSocket, host::Union{IPv4, IPv6}, port::Integer) end host_in = Ref(hton(host.host)) uv_error("connect", ccall(:jl_tcp_connect, Int32, (Ptr{Cvoid}, Ptr{Cvoid}, UInt16, Ptr{Cvoid}, Cint), - sock, host_in, hton(UInt16(port)), @cfunction(uv_connectcb, Cvoid, (Ptr{Cvoid}, Cint)), + sock, host_in, hton(UInt16(port)), @cfunction(uv_connectcb_tcp, Cvoid, (Ptr{Cvoid}, Cint)), host isa IPv6)) sock.status = StatusConnecting iolock_end() diff --git a/stdlib/Sockets/src/addrinfo.jl b/stdlib/Sockets/src/addrinfo.jl index 8e12a41f08e3b..116755cf6b431 100644 --- a/stdlib/Sockets/src/addrinfo.jl +++ b/stdlib/Sockets/src/addrinfo.jl @@ -90,7 +90,7 @@ function getalladdrinfo(host::String) finally Base.sigatomic_end() iolock_begin() - q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) + q = ct.queue; q === nothing || Base.list_deletefirst!(q::Base.IntrusiveLinkedList{Task}, ct) if uv_req_data(req) != C_NULL # req is still alive, # so make sure we don't get spurious notifications later @@ -223,7 +223,7 @@ function getnameinfo(address::Union{IPv4, IPv6}) finally Base.sigatomic_end() iolock_begin() - q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) + q = ct.queue; q === nothing || Base.list_deletefirst!(q::Base.IntrusiveLinkedList{Task}, ct) if uv_req_data(req) != C_NULL # req is still alive, # so make sure we don't get spurious notifications later diff --git a/test/trimming/Makefile b/test/trimming/Makefile index c3145765655e7..2f29292d10bb5 100644 --- a/test/trimming/Makefile +++ b/test/trimming/Makefile @@ -33,11 +33,14 @@ JULIAC_BUILDSCRIPT := $(shell $(JULIA) -e 'print(joinpath(Sys.BINDIR, Base.DATAR #============================================================================= -release: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) +release: $(BIN)/hello$(EXE) $(BIN)/trimmability$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a: $(SRCDIR)/hello.jl $(JULIAC_BUILDSCRIPT) $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true +$(BIN)/trimmability-o.a: $(SRCDIR)/trimmability.jl $(JULIAC_BUILDSCRIPT) + $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true + $(BIN)/basic_jll-o.a: $(SRCDIR)/basic_jll.jl $(JULIAC_BUILDSCRIPT) $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) -e "using Pkg; Pkg.instantiate()" $(JULIA) -t 1 -J $(JULIA_LIBDIR)/julia/sys.$(SHLIB_EXT) --startup-file=no --history-file=no --project=$(SRCDIR) --output-o $@ --output-incremental=no --strip-ir --strip-metadata --experimental --trim $(JULIAC_BUILDSCRIPT) $< --output-exe true @@ -45,14 +48,17 @@ $(BIN)/basic_jll-o.a: $(SRCDIR)/basic_jll.jl $(JULIAC_BUILDSCRIPT) $(BIN)/hello$(EXE): $(BIN)/hello-o.a $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) +$(BIN)/trimmability$(EXE): $(BIN)/trimmability-o.a + $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) + $(BIN)/basic_jll$(EXE): $(BIN)/basic_jll-o.a $(CC) -o $@ $(WHOLE_ARCHIVE) $< $(NO_WHOLE_ARCHIVE) $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) -check: $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) +check: $(BIN)/hello$(EXE) $(BIN)/trimmability$(EXE) $(BIN)/basic_jll$(EXE) $(JULIA) --depwarn=error $(SRCDIR)/trimming.jl $< clean: - -rm -f $(BIN)/hello$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/basic_jll-o.a + -rm -f $(BIN)/hello$(EXE) $(BIN)/trimmability$(EXE) $(BIN)/basic_jll$(EXE) $(BIN)/hello-o.a $(BIN)/trimmability-o.a $(BIN)/basic_jll-o.a .PHONY: release clean check diff --git a/test/trimming/hello.jl b/test/trimming/hello.jl index a00a799ed02dd..620a55b171544 100644 --- a/test/trimming/hello.jl +++ b/test/trimming/hello.jl @@ -1,37 +1,6 @@ -world::String = "world!" -const str = OncePerProcess{String}() do - return "Hello, " * world -end - -abstract type Shape end -struct Square <: Shape - side::Float64 -end -struct Circle <: Shape - radius::Float64 -end -area(s::Square) = s.side^2 -area(c::Circle) = pi*c.radius^2 - -sum_areas(v::Vector{Shape}) = sum(area, v) +# Test that minimal executable size stays low function @main(args::Vector{String})::Cint - println(Core.stdout, str()) - println(Core.stdout, PROGRAM_FILE) - foreach(x->println(Core.stdout, x), args) - - # test map/mapreduce; should work but relies on inlining and other optimizations - # test that you can dispatch to some number of concrete cases - println(Core.stdout, sum_areas(Shape[Circle(1), Square(2)])) - - arr = rand(10) - sorted_arr = sort(arr) - tot = sum(sorted_arr) - tot = prod(sorted_arr) - a = any(x -> x > 0, sorted_arr) - b = all(x -> x >= 0, sorted_arr) - c = map(x -> x^2, sorted_arr) - d = mapreduce(x -> x^2, +, sorted_arr) - # e = reduce(xor, rand(Int, 10)) + println(Core.stdout, "Hello, world!") return 0 end diff --git a/test/trimming/trimmability.jl b/test/trimming/trimmability.jl new file mode 100644 index 0000000000000..041f3621216a6 --- /dev/null +++ b/test/trimming/trimmability.jl @@ -0,0 +1,52 @@ +# Test that various constructs support trimming + +using Sockets + +world::String = "world!" +const str = OncePerProcess{String}() do + return "Hello, " * world +end + +abstract type Shape end +struct Square <: Shape + side::Float64 +end +struct Circle <: Shape + radius::Float64 +end +area(s::Square) = s.side^2 +area(c::Circle) = pi*c.radius^2 + +sum_areas(v::Vector{Shape}) = sum(area, v) + +function @main(args::Vector{String})::Cint + println(Core.stdout, str()) + println(Core.stdout, PROGRAM_FILE) + foreach(x->println(Core.stdout, x), args) + + # test map/mapreduce; should work but relies on inlining and other optimizations + # test that you can dispatch to some number of concrete cases + println(Core.stdout, sum_areas(Shape[Circle(1), Square(2)])) + + arr = rand(10) + sorted_arr = sort(arr) + tot = sum(sorted_arr) + tot = prod(sorted_arr) + a = any(x -> x > 0, sorted_arr) + b = all(x -> x >= 0, sorted_arr) + c = map(x -> x^2, sorted_arr) + d = mapreduce(x -> x^2, +, sorted_arr) + # e = reduce(xor, rand(Int, 10)) + + try + sock = connect("localhost", 4900) + if isopen(sock) + write(sock, "Hello") + flush(sock) + close(sock) + end + catch + end + + return 0 +end diff --git a/test/trimming/trimming.jl b/test/trimming/trimming.jl index ed43cdc5851e1..07e9d92871f19 100644 --- a/test/trimming/trimming.jl +++ b/test/trimming/trimming.jl @@ -6,8 +6,11 @@ bindir = dirname(ARGS[1]) let exe_suffix = splitext(Base.julia_exename())[2] hello_exe = joinpath(bindir, "hello" * exe_suffix) - @test readchomp(`$hello_exe arg1 arg2`) == "Hello, world!\n$hello_exe\narg1\narg2\n$(4.0+pi)" - @test filesize(hello_exe) < 2_500_000 + @test readchomp(`$hello_exe arg1 arg2`) == "Hello, world!" + @test filesize(hello_exe) < 1_900_000 + + trimmability_exe = joinpath(bindir, "trimmability" * exe_suffix) + @test readchomp(`$trimmability_exe arg1 arg2`) == "Hello, world!\n$trimmability_exe\narg1\narg2\n$(4.0+pi)" basic_jll_exe = joinpath(bindir, "basic_jll" * exe_suffix) lines = split(readchomp(`$basic_jll_exe`), "\n")