• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37999

02 Feb 2025 07:22AM UTC coverage: 17.218% (-8.3%) from 25.515%
#37999

push

local

web-flow
bpart: Start tracking backedges for bindings (#57213)

This PR adds limited backedge support for Bindings. There are two
classes of bindings that get backedges:

1. Cross-module `GlobalRef` bindings (new in this PR)
2. Any globals accesses through intrinsics (i.e. those with forward
edges from #57009)

This is a time/space trade-off for invalidation. As a result of the
first category, invalidating a binding now only needs to scan all the
methods defined in the same module as the binding. At the same time, it
is anticipated that most binding references are to bindings in the same
module, keeping the list of bindings that need explicit (back)edges
small.

7 of 30 new or added lines in 3 files covered. (23.33%)

4235 existing lines in 124 files now uncovered.

7882 of 45779 relevant lines covered (17.22%)

98289.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.29
/stdlib/Sockets/src/addrinfo.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    DNSError
5

6
The type of exception thrown when an error occurs in DNS lookup.
7
The `host` field indicates the host URL string.
8
The `code` field indicates the error code based on libuv.
9
"""
10
struct DNSError <: Exception
11
    host::String
×
12
    code::Int32
13
end
14

15
function show(io::IO, err::DNSError)
×
16
    print(io, "DNSError: ", err.host, ", ", Base.struverror(err.code),
×
17
                                      " (", Base.uverrorname(err.code), ")")
18
end
19

20
function uv_getaddrinfocb(req::Ptr{Cvoid}, status::Cint, addrinfo::Ptr{Cvoid})
×
21
    data = uv_req_data(req)
×
22
    if data != C_NULL
×
23
        t = unsafe_pointer_to_objref(data)::Task
×
24
        uv_req_set_data(req, C_NULL)
×
25
        if status != 0 || addrinfo == C_NULL
×
26
            schedule(t, _UVError("getaddrinfo", status))
×
27
        else
28
            freeaddrinfo = addrinfo
×
29
            addrs = IPAddr[]
×
30
            while addrinfo != C_NULL
×
31
                sockaddr = ccall(:jl_sockaddr_from_addrinfo, Ptr{Cvoid}, (Ptr{Cvoid},), addrinfo)
×
32
                if ccall(:jl_sockaddr_is_ip4, Int32, (Ptr{Cvoid},), sockaddr) == 1
×
33
                    ip4addr = ccall(:jl_sockaddr_host4, UInt32, (Ptr{Cvoid},), sockaddr)
×
34
                    push!(addrs, IPv4(ntoh(ip4addr)))
×
35
                elseif ccall(:jl_sockaddr_is_ip6, Int32, (Ptr{Cvoid},), sockaddr) == 1
×
36
                    ip6addr = Ref{UInt128}()
×
37
                    scope_id = ccall(:jl_sockaddr_host6, UInt32, (Ptr{Cvoid}, Ptr{UInt128}), sockaddr, ip6addr)
×
38
                    push!(addrs, IPv6(ntoh(ip6addr[])))
×
39
                end
40
                addrinfo = ccall(:jl_next_from_addrinfo, Ptr{Cvoid}, (Ptr{Cvoid},), addrinfo)
×
41
            end
×
42
            ccall(:uv_freeaddrinfo, Cvoid, (Ptr{Cvoid},), freeaddrinfo)
×
43
            schedule(t, addrs)
×
44
        end
45
    else
46
        # no owner for this req, safe to just free it
47
        Libc.free(req)
×
48
    end
49
    nothing
×
50
end
51

52
"""
53
    getalladdrinfo(host::AbstractString) -> Vector{IPAddr}
54

55
Gets all of the IP addresses of the `host`.
56
Uses the operating system's underlying `getaddrinfo` implementation, which may do a DNS lookup.
57

58
# Examples
59
```julia-repl
60
julia> getalladdrinfo("google.com")
61
2-element Vector{IPAddr}:
62
 ip"172.217.6.174"
63
 ip"2607:f8b0:4000:804::200e"
64
```
65
"""
66
function getalladdrinfo(host::String)
×
67
    req = Libc.malloc(Base._sizeof_uv_getaddrinfo)
×
68
    uv_req_set_data(req, C_NULL) # in case we get interrupted before arriving at the wait call
×
69
    iolock_begin()
×
70
    status = ccall(:jl_getaddrinfo, Int32, (Ptr{Cvoid}, Ptr{Cvoid}, Cstring, Ptr{Cvoid}, Ptr{Cvoid}),
×
71
                   eventloop(), req, host, #=service=#C_NULL,
UNCOV
72
                   @cfunction(uv_getaddrinfocb, Cvoid, (Ptr{Cvoid}, Cint, Ptr{Cvoid})))
×
73
    if status < 0
×
74
        Libc.free(req)
×
75
        if status == UV_EINVAL
×
76
            throw(ArgumentError("Invalid getaddrinfo argument"))
×
77
        elseif status == UV_ENOMEM || status == UV_ENOBUFS
×
78
            throw(OutOfMemoryError())
×
79
        end
80
        uv_error("getaddrinfo", status)
×
81
    end
82
    ct = current_task()
×
83
    preserve_handle(ct)
×
84
    Base.sigatomic_begin()
×
85
    uv_req_set_data(req, ct)
×
86
    iolock_end()
×
87
    r = try
×
88
        Base.sigatomic_end()
×
89
        wait()
×
90
    finally
91
        Base.sigatomic_end()
×
92
        iolock_begin()
×
93
        q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct)
×
94
        if uv_req_data(req) != C_NULL
×
95
            # req is still alive,
96
            # so make sure we don't get spurious notifications later
97
            uv_req_set_data(req, C_NULL)
×
98
            ccall(:uv_cancel, Int32, (Ptr{Cvoid},), req) # try to let libuv know we don't care anymore
×
99
        else
100
            # done with req
101
            Libc.free(req)
×
102
        end
103
        iolock_end()
×
104
        unpreserve_handle(ct)
×
105
    end
106
    if isa(r, IOError)
×
107
        code = r.code
×
108
        if code in (UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS,
×
109
                    UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL,
110
                    UV_EAI_FAMILY, UV_EAI_NODATA, UV_EAI_NONAME,
111
                    UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE,
112
                    UV_EAI_SOCKTYPE)
113
            throw(DNSError(host, code))
×
114
        elseif code == UV_EAI_MEMORY
×
115
            throw(OutOfMemoryError())
×
116
        else
117
            throw(r)
×
118
        end
119
    end
120
    return r::Vector{IPAddr}
×
121
end
122
getalladdrinfo(host::AbstractString) = getalladdrinfo(String(host))
×
123

124
"""
125
    getaddrinfo(host::AbstractString, IPAddr) -> IPAddr
126

127
Gets the first IP address of the `host` of the specified `IPAddr` type.
128
Uses the operating system's underlying getaddrinfo implementation, which may do
129
a DNS lookup.
130

131
# Examples
132
```julia-repl
133
julia> getaddrinfo("localhost", IPv6)
134
ip"::1"
135

136
julia> getaddrinfo("localhost", IPv4)
137
ip"127.0.0.1"
138
```
139
"""
140
function getaddrinfo(host::String, T::Type{<:IPAddr})
×
141
    addrs = getalladdrinfo(host)
×
142
    for addr in addrs
×
143
        if addr isa T
×
144
            return addr
×
145
        end
146
    end
×
147
    throw(DNSError(host, UV_EAI_NONAME))
×
148
end
149
getaddrinfo(host::AbstractString, T::Type{<:IPAddr}) = getaddrinfo(String(host), T)
×
150

151
"""
152
    getaddrinfo(host::AbstractString) -> IPAddr
153

154
Gets the first available IP address of `host`, which may be either an `IPv4` or
155
`IPv6` address. Uses the operating system's underlying getaddrinfo
156
implementation, which may do a DNS lookup.
157
"""
158
function getaddrinfo(host::AbstractString)
159
    addrs = getalladdrinfo(String(host))
×
160
    if !isempty(addrs)
×
161
        return addrs[begin]::Union{IPv4,IPv6}
×
162
    end
163
    throw(DNSError(host, UV_EAI_NONAME))
×
164
end
165

166
function uv_getnameinfocb(req::Ptr{Cvoid}, status::Cint, hostname::Cstring, service::Cstring)
×
167
    data = uv_req_data(req)
×
168
    if data != C_NULL
×
169
        t = unsafe_pointer_to_objref(data)::Task
×
170
        uv_req_set_data(req, C_NULL)
×
171
        if status != 0
×
172
            schedule(t, _UVError("getnameinfo", status))
×
173
        else
174
            schedule(t, unsafe_string(hostname))
×
175
        end
176
    else
177
        # no owner for this req, safe to just free it
178
        Libc.free(req)
×
179
    end
180
    nothing
×
181
end
182

183
"""
184
    getnameinfo(host::IPAddr) -> String
185

186
Performs a reverse-lookup for IP address to return a hostname and service
187
using the operating system's underlying `getnameinfo` implementation.
188

189
# Examples
190
```julia-repl
191
julia> getnameinfo(IPv4("8.8.8.8"))
192
"google-public-dns-a.google.com"
193
```
194
"""
195
function getnameinfo(address::Union{IPv4, IPv6})
×
196
    req = Libc.malloc(Base._sizeof_uv_getnameinfo)
×
197
    uv_req_set_data(req, C_NULL) # in case we get interrupted before arriving at the wait call
×
198
    port = hton(UInt16(0))
×
199
    flags = 0
×
200
    uvcb = @cfunction(uv_getnameinfocb, Cvoid, (Ptr{Cvoid}, Cint, Cstring, Cstring))
×
201
    status = UV_EINVAL
×
202
    host_in = Ref(hton(address.host))
×
203
    iolock_begin()
×
204
    status = ccall(:jl_getnameinfo, Int32, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, UInt16, Cint, Ptr{Cvoid}, Cint),
×
205
                   eventloop(), req, host_in, port, flags, uvcb, address isa IPv6)
206
    if status < 0
×
207
        Libc.free(req)
×
208
        if status == UV_EINVAL
×
209
            throw(ArgumentError("Invalid getnameinfo argument"))
×
210
        elseif status == UV_ENOMEM || status == UV_ENOBUFS
×
211
            throw(OutOfMemoryError())
×
212
        end
213
        uv_error("getnameinfo", status)
×
214
    end
215
    ct = current_task()
×
216
    preserve_handle(ct)
×
217
    Base.sigatomic_begin()
×
218
    uv_req_set_data(req, ct)
×
219
    iolock_end()
×
220
    r = try
×
221
        Base.sigatomic_end()
×
222
        wait()
×
223
    finally
224
        Base.sigatomic_end()
×
225
        iolock_begin()
×
226
        q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct)
×
227
        if uv_req_data(req) != C_NULL
×
228
            # req is still alive,
229
            # so make sure we don't get spurious notifications later
230
            uv_req_set_data(req, C_NULL)
×
231
            ccall(:uv_cancel, Int32, (Ptr{Cvoid},), req) # try to let libuv know we don't care anymore
×
232
        else
233
            # done with req
234
            Libc.free(req)
×
235
        end
236
        iolock_end()
×
237
        unpreserve_handle(ct)
×
238
    end
239
    if isa(r, IOError)
×
240
        code = r.code
×
241
        if code in (UV_EAI_ADDRFAMILY, UV_EAI_AGAIN, UV_EAI_BADFLAGS,
×
242
                    UV_EAI_BADHINTS, UV_EAI_CANCELED, UV_EAI_FAIL,
243
                    UV_EAI_FAMILY, UV_EAI_NODATA, UV_EAI_NONAME,
244
                    UV_EAI_OVERFLOW, UV_EAI_PROTOCOL, UV_EAI_SERVICE,
245
                    UV_EAI_SOCKTYPE)
246
            throw(DNSError(repr(address), code))
×
247
        elseif code == UV_EAI_MEMORY
×
248
            throw(OutOfMemoryError())
×
249
        else
250
            throw(r)
×
251
        end
252
    end
253
    return r::String
×
254
end
255

256
const _sizeof_uv_interface_address = ccall(:jl_uv_sizeof_interface_address,Int32,())
257

258
"""
259
    getipaddr() -> IPAddr
260

261
Get an IP address of the local machine, preferring IPv4 over IPv6. Throws if no
262
addresses are available.
263

264
    getipaddr(addr_type::Type{T}) where T<:IPAddr -> T
265

266
Get an IP address of the local machine of the specified type. Throws if no
267
addresses of the specified type are available.
268

269
This function is a backwards-compatibility wrapper around [`getipaddrs`](@ref).
270
New applications should use [`getipaddrs`](@ref) instead.
271

272
# Examples
273
```julia-repl
274
julia> getipaddr()
275
ip"192.168.1.28"
276

277
julia> getipaddr(IPv6)
278
ip"fe80::9731:35af:e1c5:6e49"
279
```
280

281
See also [`getipaddrs`](@ref).
282
"""
283
function getipaddr(addr_type::Type{T}) where T<:IPAddr
284
    addrs = getipaddrs(addr_type)
5✔
285
    isempty(addrs) && error("No networking interface available")
5✔
286

287
    # When `addr_type` is `IPAddr`, `addrs` contain IP addresses of all types
288
    # In that case, we prefer to return the first IPv4
289
    i = something(findfirst(ip -> ip isa IPv4, addrs), 1)
15✔
290
    return addrs[i]
5✔
291
end
292
getipaddr() = getipaddr(IPAddr)
5✔
293

294

295
"""
296
    getipaddrs(addr_type::Type{T}=IPAddr; loopback::Bool=false) where T<:IPAddr -> Vector{T}
297

298
Get the IP addresses of the local machine.
299

300
Setting the optional `addr_type` parameter to `IPv4` or `IPv6` causes only addresses of that type to be returned.
301

302
The `loopback` keyword argument dictates whether loopback addresses (e.g. `ip"127.0.0.1"`, `ip"::1"`) are included.
303

304
!!! compat "Julia 1.2"
305
    This function is available as of Julia 1.2.
306

307
# Examples
308
```julia-repl
309
julia> getipaddrs()
310
5-element Vector{IPAddr}:
311
 ip"198.51.100.17"
312
 ip"203.0.113.2"
313
 ip"2001:db8:8:4:445e:5fff:fe5d:5500"
314
 ip"2001:db8:8:4:c164:402e:7e3c:3668"
315
 ip"fe80::445e:5fff:fe5d:5500"
316

317
julia> getipaddrs(IPv6)
318
3-element Vector{IPv6}:
319
 ip"2001:db8:8:4:445e:5fff:fe5d:5500"
320
 ip"2001:db8:8:4:c164:402e:7e3c:3668"
321
 ip"fe80::445e:5fff:fe5d:5500"
322
```
323

324
See also [`islinklocaladdr`](@ref).
325
"""
326
function getipaddrs(addr_type::Type{T}=IPAddr; loopback::Bool=false) where T<:IPAddr
5✔
327
    addresses = T[]
328
    addr_ref = Ref{Ptr{UInt8}}(C_NULL)
329
    count_ref = Ref{Int32}(1)
330
    lo_present = false
331
    err = ccall(:jl_uv_interface_addresses, Int32, (Ref{Ptr{UInt8}}, Ref{Int32}), addr_ref, count_ref)
332
    uv_error("getlocalip", err)
333
    addr, count = addr_ref[], count_ref[]
334
    for i = 0:(count-1)
335
        current_addr = addr + i*_sizeof_uv_interface_address
336
        if 1 == ccall(:jl_uv_interface_address_is_internal, Int32, (Ptr{UInt8},), current_addr)
337
            lo_present = true
338
            if !loopback
339
                continue
340
            end
341
        end
342
        sockaddr = ccall(:jl_uv_interface_address_sockaddr, Ptr{Cvoid}, (Ptr{UInt8},), current_addr)
343
        if IPv4 <: T && ccall(:jl_sockaddr_is_ip4, Int32, (Ptr{Cvoid},), sockaddr) == 1
344
            push!(addresses, IPv4(ntoh(ccall(:jl_sockaddr_host4, UInt32, (Ptr{Cvoid},), sockaddr))))
345
        elseif IPv6 <: T && ccall(:jl_sockaddr_is_ip6, Int32, (Ptr{Cvoid},), sockaddr) == 1
346
            addr6 = Ref{UInt128}()
347
            scope_id = ccall(:jl_sockaddr_host6, UInt32, (Ptr{Cvoid}, Ref{UInt128},), sockaddr, addr6)
348
            push!(addresses, IPv6(ntoh(addr6[])))
349
        end
350
    end
351
    ccall(:uv_free_interface_addresses, Cvoid, (Ptr{UInt8}, Int32), addr, count)
352
    return addresses
353
end
354

355
"""
356
    islinklocaladdr(addr::IPAddr)
357

358
Tests if an IP address is a link-local address. Link-local addresses
359
are not guaranteed to be unique beyond their network segment,
360
therefore routers do not forward them. Link-local addresses are from
361
the address blocks `169.254.0.0/16` or `fe80::/10`.
362

363
# Examples
364
```julia
365
filter(!islinklocaladdr, getipaddrs())
366
```
367
"""
368
function islinklocaladdr(addr::IPv4)
×
369
    # RFC 3927
370
    return (addr.host &
×
371
            0xFFFF0000) ==
372
            0xA9FE0000
373
end
374
function islinklocaladdr(addr::IPv6)
×
375
    # RFC 4291
376
    return (addr.host &
×
377
            0xFFC00000000000000000000000000000) ==
378
            0xFE800000000000000000000000000000
379
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc