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

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

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

63.58
/base/libc.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
module Libc
4
@doc """
5
Interface to libc, the C standard library.
6
""" Libc
7

8
import Base: transcode, windowserror, show
9
import Core.Intrinsics: bitcast
10

11
export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, calloc, realloc,
12
    errno, strerror, flush_cstdio, systemsleep, time, transcode
13
if Sys.iswindows()
14
    export GetLastError, FormatMessage
15
end
16

17
include(string(length(Core.ARGS) >= 2 ? Core.ARGS[2] : "", "errno_h.jl"))  # include($BUILDROOT/base/errno_h.jl)
18

19
## RawFD ##
20

21
# Wrapper for an OS file descriptor (on both Unix and Windows)
22
"""
23
    RawFD
24

25
Primitive type which wraps the native OS file descriptor.
26
`RawFD`s can be passed to methods like [`stat`](@ref) to
27
discover information about the underlying file, and can
28
also be used to open streams, with the `RawFD` describing
29
the OS file backing the stream.
30
"""
31
primitive type RawFD 32 end
32
RawFD(fd::Integer) = bitcast(RawFD, Cint(fd))
9,598✔
33
RawFD(fd::RawFD) = fd
×
34
Base.cconvert(::Type{Cint}, fd::RawFD) = bitcast(Cint, fd)
3,172✔
35

36
dup(x::RawFD) = ccall((@static Sys.iswindows() ? :_dup : :dup), RawFD, (RawFD,), x)
4✔
37
dup(src::RawFD, target::RawFD) = systemerror("dup", -1 ==
316✔
38
    ccall((@static Sys.iswindows() ? :_dup2 : :dup2), Int32,
39
                (RawFD, RawFD), src, target))
40

41
show(io::IO, fd::RawFD) = print(io, "RawFD(", bitcast(UInt32, fd), ')')  # avoids invalidation via show_default
11✔
42

43
# Wrapper for an OS file descriptor (for Windows)
44
if Sys.iswindows()
45
    primitive type WindowsRawSocket sizeof(Ptr) * 8 end # On Windows file descriptors are HANDLE's and 64-bit on 64-bit Windows
46
    WindowsRawSocket(handle::Ptr{Cvoid}) = bitcast(WindowsRawSocket, handle)
×
47
    WindowsRawSocket(handle::WindowsRawSocket) = handle
×
48

49
    Base.cconvert(::Type{Ptr{Cvoid}}, fd::WindowsRawSocket) = bitcast(Ptr{Cvoid}, fd)
×
50
    _get_osfhandle(fd::RawFD) = ccall(:_get_osfhandle, WindowsRawSocket, (RawFD,), fd)
×
51
    _get_osfhandle(fd::WindowsRawSocket) = fd
×
52
    function dup(src::WindowsRawSocket)
×
53
        new_handle = Ref(WindowsRawSocket(Ptr{Cvoid}(-1)))
×
54
        my_process = ccall(:GetCurrentProcess, stdcall, Ptr{Cvoid}, ())
×
55
        DUPLICATE_SAME_ACCESS = 0x2
×
56
        status = ccall(:DuplicateHandle, stdcall, Int32,
×
57
            (Ptr{Cvoid}, WindowsRawSocket, Ptr{Cvoid}, Ptr{WindowsRawSocket}, UInt32, Int32, UInt32),
58
            my_process, src, my_process, new_handle, 0, false, DUPLICATE_SAME_ACCESS)
59
        windowserror("dup failed", status == 0)
×
60
        return new_handle[]
×
61
    end
62
    function dup(src::WindowsRawSocket, target::RawFD)
×
63
        fd = ccall(:_open_osfhandle, RawFD, (WindowsRawSocket, Int32), dup(src), 0)
×
64
        dup(fd, target)
×
65
        ccall(:_close, Int32, (RawFD,), fd)
×
66
        nothing
×
67
    end
68

69
else
70
    _get_osfhandle(fd::RawFD) = fd
×
71
end
72

73
## FILE (not auto-finalized) ##
74

75
struct FILE
76
    ptr::Ptr{Cvoid}
5✔
77
end
78

79
modestr(s::IO) = modestr(isreadable(s), iswritable(s))
4✔
80
modestr(r::Bool, w::Bool) = r ? (w ? "r+" : "r") : (w ? "w" : throw(ArgumentError("neither readable nor writable")))
9✔
81

82
function FILE(fd::RawFD, mode)
5✔
83
    FILEp = ccall((@static Sys.iswindows() ? :_fdopen : :fdopen), Ptr{Cvoid}, (Cint, Cstring), fd, mode)
5✔
84
    systemerror("fdopen", FILEp == C_NULL)
5✔
85
    FILE(FILEp)
5✔
86
end
87

88
function FILE(s::IO)
4✔
89
    f = FILE(dup(RawFD(fd(s))),modestr(s))
4✔
90
    seek(f, position(s))
4✔
91
    f
4✔
92
end
93

94
Base.unsafe_convert(T::Union{Type{Ptr{Cvoid}},Type{Ptr{FILE}}}, f::FILE) = convert(T, f.ptr)
2✔
95
Base.close(f::FILE) = systemerror("fclose", ccall(:fclose, Cint, (Ptr{Cvoid},), f.ptr) != 0)
5✔
96

97
function Base.seek(h::FILE, offset::Integer)
6✔
98
    systemerror("fseek", ccall(:fseek, Cint, (Ptr{Cvoid}, Clong, Cint),
6✔
99
                               h.ptr, offset, 0) != 0)
100
    h
6✔
101
end
102

103
Base.position(h::FILE) = ccall(:ftell, Clong, (Ptr{Cvoid},), h.ptr)
4✔
104

105
# flush C stdio output from external libraries
106

107
"""
108
    flush_cstdio()
109

110
Flushes the C `stdout` and `stderr` streams (which may have been written to by external C code).
111
"""
112
flush_cstdio() = ccall(:jl_flush_cstdio, Cvoid, ())
1✔
113

114
## time-related functions ##
115

116
# TODO: check for usleep errors?
117
if Sys.isunix()
118
    systemsleep(s::Real) = ccall(:usleep, Int32, (UInt32,), round(UInt32, s*1e6))
52✔
119
elseif Sys.iswindows()
120
    function systemsleep(s::Real)
×
121
        ccall(:Sleep, stdcall, Cvoid, (UInt32,), round(UInt32, s * 1e3))
×
122
        return Int32(0)
×
123
    end
124
else
125
    error("systemsleep undefined for this OS")
126
end
127
"""
128
    systemsleep(s::Real)
129

130
Suspends execution for `s` seconds.
131
This function does not yield to Julia's scheduler and therefore blocks
132
the Julia thread that it is running on for the duration of the sleep time.
133

134
See also [`sleep`](@ref).
135
"""
136
systemsleep
137

138
struct TimeVal
139
   sec::Int64
140
   usec::Int64
141
end
142

143
function TimeVal()
×
144
    tv = Ref{TimeVal}()
486✔
145
    status = ccall(:jl_gettimeofday, Cint, (Ref{TimeVal},), tv)
486✔
146
    status != 0 && error("unable to determine current time: ", status)
486✔
147
    return tv[]
486✔
148
end
149

150
"""
151
    TmStruct([seconds])
152

153
Convert a number of seconds since the epoch to broken-down format, with fields `sec`, `min`,
154
`hour`, `mday`, `month`, `year`, `wday`, `yday`, and `isdst`.
155
"""
156
mutable struct TmStruct
157
    sec::Int32
158
    min::Int32
159
    hour::Int32
160
    mday::Int32
161
    month::Int32
162
    year::Int32
163
    wday::Int32
164
    yday::Int32
165
    isdst::Int32
166
    # on some platforms the struct is 14 words, even though 9 are specified
167
    _10::Int32
168
    _11::Int32
169
    _12::Int32
170
    _13::Int32
171
    _14::Int32
172

173
    TmStruct(sec, min, hour, mday, month, year, wday, yday, isdst) =
1✔
174
        new(sec, min, hour, mday, month, year, wday, yday, isdst, 0,0,0,0,0)
175
    TmStruct() = new(0,0,0,0,0,0,0,0,0,0,0,0,0,0)
503✔
176
    function TmStruct(t::Real)
496✔
177
        t = floor(t)
10✔
178
        tm = TmStruct()
496✔
179
        # TODO: add support for UTC via gmtime_r()
180
        ccall(:localtime_r, Ptr{TmStruct}, (Ref{Int}, Ref{TmStruct}), t, tm)
496✔
181
        return tm
496✔
182
    end
183
end
184

185
"""
186
    strftime([format], time)
187

188
Convert time, given as a number of seconds since the epoch or a `TmStruct`, to a formatted
189
string using the given format. Supported formats are the same as those in the standard C
190
library.
191
"""
192
strftime(t) = strftime("%c", t)
×
193
strftime(fmt::AbstractString, t::Real) = strftime(fmt, TmStruct(t))
10✔
194
# Use wcsftime instead of strftime to support different locales
195
function strftime(fmt::AbstractString, tm::TmStruct)
16✔
196
    wctimestr = Vector{Cwchar_t}(undef, 128)
16✔
197
    n = ccall(:wcsftime, Csize_t, (Ptr{Cwchar_t}, Csize_t, Cwstring, Ref{TmStruct}),
16✔
198
              wctimestr, length(wctimestr), fmt, tm)
199
    n == 0 && return ""
16✔
200
    return transcode(String, resize!(wctimestr, n))
16✔
201
end
202

203
"""
204
    strptime([format], timestr)
205

206
Parse a formatted time string into a `TmStruct` giving the seconds, minute, hour, date, etc.
207
Supported formats are the same as those in the standard C library. On some platforms,
208
timezones will not be parsed correctly. If the result of this function will be passed to
209
`time` to convert it to seconds since the epoch, the `isdst` field should be filled in
210
manually. Setting it to `-1` will tell the C library to use the current system settings to
211
determine the timezone.
212
"""
213
strptime(timestr::AbstractString) = strptime("%c", timestr)
×
214
function strptime(fmt::AbstractString, timestr::AbstractString)
7✔
215
    tm = TmStruct()
7✔
216
    r = ccall(:strptime, Cstring, (Cstring, Cstring, Ref{TmStruct}), timestr, fmt, tm)
7✔
217
    # the following would tell mktime() that this is a local time, and that
218
    # it should try to guess the timezone. not sure if/how this should be
219
    # exposed in the API.
220
    # tm.isdst = -1
221
    if r == C_NULL
7✔
222
        # TODO: better error message
223
        throw(ArgumentError("invalid arguments"))
×
224
    end
225
    @static if Sys.isapple()
×
226
        # if we didn't explicitly parse the weekday or year day, use mktime
227
        # to fill them in automatically.
228
        if !occursin(r"([^%]|^)%(a|A|j|w|Ow)"a, fmt)
229
            ccall(:mktime, Int, (Ref{TmStruct},), tm)
230
        end
231
    end
232
    return tm
7✔
233
end
234

235
# system date in seconds
236

237
"""
238
    time(t::TmStruct) -> Float64
239

240
Converts a `TmStruct` struct to a number of seconds since the epoch.
241
"""
242
time(tm::TmStruct) = Float64(ccall(:mktime, Int, (Ref{TmStruct},), tm))
×
243

244
"""
245
    time() -> Float64
246

247
Get the system time in seconds since the epoch, with fairly high (typically, microsecond) resolution.
248
"""
249
time() = ccall(:jl_clock_now, Float64, ())
31,544✔
250

251
## process-related functions ##
252

253
"""
254
    getpid() -> Int32
255

256
Get Julia's process ID.
257
"""
258
getpid() = ccall(:uv_os_getpid, Int32, ())
325✔
259

260
## network functions ##
261

262
"""
263
    gethostname() -> String
264

265
Get the local machine's host name.
266
"""
267
function gethostname()
136✔
268
    hn = Vector{UInt8}(undef, 256)
136✔
269
    err = @static if Sys.iswindows()
×
270
        ccall(:gethostname, stdcall, Int32, (Ptr{UInt8}, UInt32), hn, length(hn))
271
    else
272
        ccall(:gethostname, Int32, (Ptr{UInt8}, UInt), hn, length(hn))
136✔
273
    end
274
    systemerror("gethostname", err != 0)
136✔
275
    return GC.@preserve hn unsafe_string(pointer(hn))
136✔
276
end
277

278
## system error handling ##
279

280
"""
281
    errno([code])
282

283
Get the value of the C library's `errno`. If an argument is specified, it is used to set the
284
value of `errno`.
285

286
The value of `errno` is only valid immediately after a `ccall` to a C library routine that
287
sets it. Specifically, you cannot call `errno` at the next prompt in a REPL, because lots of
288
code is executed between prompts.
289
"""
290
errno() = ccall(:jl_errno, Cint, ())
13✔
291
errno(e::Integer) = ccall(:jl_set_errno, Cvoid, (Cint,), e)
×
292

293
"""
294
    strerror(n=errno())
295

296
Convert a system call error code to a descriptive string
297
"""
298
strerror(e::Integer) = unsafe_string(ccall(:strerror, Cstring, (Int32,), e))
3✔
299
strerror() = strerror(errno())
×
300

301
"""
302
    GetLastError()
303

304
Call the Win32 `GetLastError` function [only available on Windows].
305
"""
306
function GetLastError end
307

308
"""
309
    FormatMessage(n=GetLastError())
310

311
Convert a Win32 system call error code to a descriptive string [only available on Windows].
312
"""
313
function FormatMessage end
314

315
if Sys.iswindows()
316
    GetLastError() = ccall(:GetLastError, stdcall, UInt32, ())
×
317

318
    FormatMessage(e) = FormatMessage(UInt32(e))
×
319
    function FormatMessage(e::UInt32=GetLastError())
×
320
        FORMAT_MESSAGE_ALLOCATE_BUFFER = UInt32(0x100)
×
321
        FORMAT_MESSAGE_FROM_SYSTEM = UInt32(0x1000)
×
322
        FORMAT_MESSAGE_IGNORE_INSERTS = UInt32(0x200)
×
323
        FORMAT_MESSAGE_MAX_WIDTH_MASK = UInt32(0xFF)
×
324
        lpMsgBuf = Ref{Ptr{UInt16}}()
×
325
        lpMsgBuf[] = 0
×
326
        len = ccall(:FormatMessageW, stdcall, UInt32, (UInt32, Ptr{Cvoid}, UInt32, UInt32, Ptr{Ptr{UInt16}}, UInt32, Ptr{Cvoid}),
×
327
                    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
328
                    C_NULL, e, 0, lpMsgBuf, 0, C_NULL)
329
        p = lpMsgBuf[]
×
330
        len == 0 && return ""
×
331
        buf = Vector{UInt16}(undef, len)
×
332
        GC.@preserve buf unsafe_copyto!(pointer(buf), p, len)
×
333
        ccall(:LocalFree, stdcall, Ptr{Cvoid}, (Ptr{Cvoid},), p)
×
334
        return transcode(String, buf)
×
335
    end
336
end
337

338
## Memory related ##
339

340
"""
341
    free(addr::Ptr)
342

343
Call `free` from the C standard library. Only use this on memory obtained from [`malloc`](@ref), not
344
on pointers retrieved from other C libraries. [`Ptr`](@ref) objects obtained from C libraries should
345
be freed by the free functions defined in that library, to avoid assertion failures if
346
multiple `libc` libraries exist on the system.
347
"""
348
free(p::Ptr) = ccall(:free, Cvoid, (Ptr{Cvoid},), p)
693,610✔
349

350
"""
351
    malloc(size::Integer) -> Ptr{Cvoid}
352

353
Call `malloc` from the C standard library.
354
"""
355
malloc(size::Integer) = ccall(:malloc, Ptr{Cvoid}, (Csize_t,), size)
696,184✔
356

357
"""
358
    realloc(addr::Ptr, size::Integer) -> Ptr{Cvoid}
359

360
Call `realloc` from the C standard library.
361

362
See warning in the documentation for [`free`](@ref) regarding only using this on memory originally
363
obtained from [`malloc`](@ref).
364
"""
365
realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t), p, size)
×
366

367
"""
368
    calloc(num::Integer, size::Integer) -> Ptr{Cvoid}
369

370
Call `calloc` from the C standard library.
371
"""
372
calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Cvoid}, (Csize_t, Csize_t), num, size)
×
373

374
free(p::Cstring) = free(convert(Ptr{UInt8}, p))
1✔
375
free(p::Cwstring) = free(convert(Ptr{Cwchar_t}, p))
×
376

377
## Random numbers ##
378

379
# Access to very high quality (kernel) randomness
380
function getrandom!(A::Union{Array,Base.RefValue})
19,149✔
381
    ret = ccall(:uv_random, Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Csize_t,   Cuint, Ptr{Cvoid}),
44,065✔
382
                                   C_NULL,     C_NULL,     A,          sizeof(A), 0,     C_NULL)
383
    Base.uv_error("getrandom", ret)
44,065✔
384
    return A
44,065✔
385
end
386
_make_uint64_seed() = getrandom!(Base.RefValue{UInt64}())[]
1✔
387

388
# To limit dependency on rand functionality implemented in the Random module,
389
# Libc.rand is used in Base (it also is independent from Random.seed, so is
390
# only affected by `Libc.srand(seed)` calls)
391
"""
392
    rand([T::Type]=UInt32)
393

394
Generate a random number of type `T`. `T` can be `UInt32` or `Float64`.
395
"""
396
rand() = ccall(:jl_rand, UInt64, ()) % UInt32
8,143✔
397
rand(::Type{UInt32}) = rand()
×
398
rand(::Type{Float64}) = rand() * 2.0^-32
143✔
399

400
"""
401
    srand([seed])
402

403
Set a value for the current global `seed`.
404
"""
405
function srand(seed::Integer=_make_uint64_seed())
3✔
406
    ccall(:jl_srand, Cvoid, (UInt64,), seed % UInt64)
3✔
407
end
408

409
struct Cpasswd
410
   username::Cstring
411
   uid::Culong
412
   gid::Culong
413
   shell::Cstring
414
   homedir::Cstring
415
   gecos::Cstring
416
   Cpasswd() = new(C_NULL, typemax(Culong), typemax(Culong), C_NULL, C_NULL, C_NULL)
7✔
417
end
418
mutable struct Cgroup
419
    groupname::Cstring # group name
420
    gid::Culong        # group ID
421
    mem::Ptr{Cstring}  # group members
422
    Cgroup() = new(C_NULL, typemax(Culong), C_NULL)
7✔
423
end
424
struct Passwd
425
    username::String
7✔
426
    uid::UInt
427
    gid::UInt
428
    shell::String
429
    homedir::String
430
    gecos::String
431
end
432
struct Group
433
    groupname::String
7✔
434
    gid::UInt
435
    mem::Vector{String}
436
end
437

438
function getpwuid(uid::Unsigned, throw_error::Bool=true)
7✔
439
    ref_pd = Ref(Cpasswd())
7✔
440
    ret = ccall(:uv_os_get_passwd2, Cint, (Ref{Cpasswd}, Culong), ref_pd, uid)
7✔
441
    if ret != 0
7✔
442
        throw_error && Base.uv_error("getpwuid", ret)
×
443
        return
×
444
    end
445
    pd = ref_pd[]
7✔
446
    pd = Passwd(
14✔
447
        pd.username == C_NULL ? "" : unsafe_string(pd.username),
448
        pd.uid,
449
        pd.gid,
450
        pd.shell == C_NULL ? "" : unsafe_string(pd.shell),
451
        pd.homedir == C_NULL ? "" : unsafe_string(pd.homedir),
452
        pd.gecos == C_NULL ? "" : unsafe_string(pd.gecos),
453
    )
454
    ccall(:uv_os_free_passwd, Cvoid, (Ref{Cpasswd},), ref_pd)
7✔
455
    return pd
7✔
456
end
457
function getgrgid(gid::Unsigned, throw_error::Bool=true)
7✔
458
    ref_gp = Ref(Cgroup())
7✔
459
    ret = ccall(:uv_os_get_group, Cint, (Ref{Cgroup}, Culong), ref_gp, gid)
7✔
460
    if ret != 0
7✔
461
        throw_error && Base.uv_error("getgrgid", ret)
×
462
        return
×
463
    end
464
    gp = ref_gp[]
7✔
465
    members = String[]
7✔
466
    if gp.mem != C_NULL
7✔
467
        while true
14✔
468
            mem = unsafe_load(gp.mem, length(members) + 1)
14✔
469
            mem == C_NULL && break
14✔
470
            push!(members, unsafe_string(mem))
7✔
471
        end
7✔
472
    end
473
    gp = Group(
14✔
474
         gp.groupname == C_NULL ? "" : unsafe_string(gp.groupname),
475
         gp.gid,
476
         members,
477
    )
478
    ccall(:uv_os_free_group, Cvoid, (Ref{Cgroup},), ref_gp)
7✔
479
    return gp
7✔
480
end
481

482
getuid() = ccall(:jl_getuid, Culong, ())
1✔
483
geteuid() = ccall(:jl_geteuid, Culong, ())
3✔
484

485
# Include dlopen()/dlpath() code
486
include("libdl.jl")
487
using .Libdl
488

489
end # module
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

© 2025 Coveralls, Inc