Skip to content

Commit

Permalink
when loading code for internal purposes, load stdlib files directly(#…
Browse files Browse the repository at this point in the history
…53326)

This bypasses DEPOT_PATH, LOAD_PATH, and stale checks when loading
known stdlib code for known purposes from known locations, specifically
to avoid the problem that I cannot fix my tools because I have used my
tools to break my tools.

This helps avoid the situation that the user can break important Pkg,
REPL, Socket or similar features simply because they chose to remove
`@stdlib` from their environment. For example, if you make an edit to
REPL, then this will trigger recompilation and load the edited version:
```
$ ./julia -e 'using REPL' -iq
┌ Info: Precompiling REPL [3fa0cd96-eef1-5676-8a61-b3b8758bbffb] (cache misses: include_dependency fsize change (2), invalid header (10), mismatched flags (1))
└ @ Base loading.jl:2643
julia>
```
But this will load the version that shipped with Julia, regardless of
the state of the cache or the source code (unless you delete the cache
files):
```
$ ./julia -iq
julia>
```

Fixes #53365
  • Loading branch information
vtjnash authored Feb 23, 2024
1 parent 2ebb896 commit ea1a0d2
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 151 deletions.
3 changes: 1 addition & 2 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,7 @@ function profile_printing_listener(cond::Base.AsyncCondition)
profile = nothing
try
while _trywait(cond)
# this call to require is mostly legal, only because Profile has no dependencies and is usually in LOAD_PATH
profile = @something(profile, require(PkgId(UUID("9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"), "Profile")))::Module
profile = @something(profile, require_stdlib(PkgId(UUID("9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"), "Profile")))::Module
invokelatest(profile.peek_report[])
if Base.get_bool_env("JULIA_PROFILE_PEEK_HEAP_SNAPSHOT", false) === true
println(stderr, "Saving heap snapshot...")
Expand Down
7 changes: 4 additions & 3 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ function exec_options(opts)
# Load Distributed module only if any of the Distributed options have been specified.
distributed_mode = (opts.worker == 1) || (opts.nprocs > 0) || (opts.machine_file != C_NULL)
if distributed_mode
let Distributed = require(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed"))
let Distributed = require_stdlib(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed"))
Core.eval(MainInclude, :(const Distributed = $Distributed))
Core.eval(Main, :(using Base.MainInclude.Distributed))
end
Expand Down Expand Up @@ -386,7 +386,8 @@ function load_InteractiveUtils(mod::Module=Main)
# load interactive-only libraries
if !isdefined(MainInclude, :InteractiveUtils)
try
let InteractiveUtils = require(PkgId(UUID(0xb77e0a4c_d291_57a0_90e8_8db25a27a240), "InteractiveUtils"))
# TODO: we have to use require_stdlib here because it is a dependency of REPL, but we would sort of prefer not to
let InteractiveUtils = require_stdlib(PkgId(UUID(0xb77e0a4c_d291_57a0_90e8_8db25a27a240), "InteractiveUtils"))
Core.eval(MainInclude, :(const InteractiveUtils = $InteractiveUtils))
end
catch ex
Expand All @@ -401,7 +402,7 @@ end
function load_REPL()
# load interactive-only libraries
try
return Base.require(PkgId(UUID(0x3fa0cd96_eef1_5676_8a61_b3b8758bbffb), "REPL"))
return Base.require_stdlib(PkgId(UUID(0x3fa0cd96_eef1_5676_8a61_b3b8758bbffb), "REPL"))
catch ex
@warn "Failed to import REPL" exception=(ex, catch_backtrace())
end
Expand Down
311 changes: 186 additions & 125 deletions base/loading.jl

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions base/stream.jl
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ function init_stdio(handle::Ptr{Cvoid})
elseif t == UV_TTY
io = TTY(handle, StatusOpen)
elseif t == UV_TCP
Sockets = require(PkgId(UUID((0x6462fe0b_24de_5631, 0x8697_dd941f90decc)), "Sockets"))
Sockets = require_stdlib(PkgId(UUID((0x6462fe0b_24de_5631, 0x8697_dd941f90decc)), "Sockets"))
io = Sockets.TCPSocket(handle, StatusOpen)
elseif t == UV_NAMED_PIPE
io = PipeEndpoint(handle, StatusOpen)
Expand Down Expand Up @@ -341,7 +341,7 @@ function open(h::OS_HANDLE)
elseif t == UV_TTY
io = TTY(h)
elseif t == UV_TCP
Sockets = require(PkgId(UUID((0x6462fe0b_24de_5631, 0x8697_dd941f90decc)), "Sockets"))
Sockets = require_stdlib(PkgId(UUID((0x6462fe0b_24de_5631, 0x8697_dd941f90decc)), "Sockets"))
io = Sockets.TCPSocket(h)
elseif t == UV_NAMED_PIPE
io = PipeEndpoint(h)
Expand Down
2 changes: 1 addition & 1 deletion base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ function runtests(tests = ["all"]; ncores::Int = ceil(Int, Sys.CPU_THREADS / 2),
catch
buf = PipeBuffer()
original_load_path = copy(Base.LOAD_PATH); empty!(Base.LOAD_PATH); pushfirst!(Base.LOAD_PATH, "@stdlib")
let InteractiveUtils = Base.require(Base, :InteractiveUtils)
let InteractiveUtils = Base.require_stdlib(Base, :InteractiveUtils)
@invokelatest InteractiveUtils.versioninfo(buf)
end
empty!(Base.LOAD_PATH); append!(Base.LOAD_PATH, original_load_path)
Expand Down
4 changes: 2 additions & 2 deletions stdlib/InteractiveUtils/src/InteractiveUtils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export peakflops
function peakflops(n::Integer=4096; eltype::DataType=Float64, ntrials::Integer=3, parallel::Bool=false)
# Base.depwarn("`peakflops` has moved to the LinearAlgebra module, " *
# "add `using LinearAlgebra` to your imports.", :peakflops)
let LinearAlgebra = Base.require(Base.PkgId(
let LinearAlgebra = Base.require_stdlib(Base.PkgId(
Base.UUID((0x37e2e46d_f89d_539d,0xb4ee_838fcccc9c8e)), "LinearAlgebra"))
return LinearAlgebra.peakflops(n, eltype=eltype, ntrials=ntrials, parallel=parallel)
end
Expand All @@ -353,7 +353,7 @@ function report_bug(kind)
if Base.locate_package(BugReportingId) === nothing
@info "Package `BugReporting` not found - attempting temporary installation"
# Create a temporary environment and add BugReporting
let Pkg = Base.require(Base.PkgId(
let Pkg = Base.require_stdlib(Base.PkgId(
Base.UUID((0x44cfe95a_1eb2_52ea,0xb672_e2afdf69b78f)), "Pkg"))
mktempdir() do tmp
old_load_path = copy(LOAD_PATH)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/LinearAlgebra/src/LinearAlgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ function peakflops(n::Integer=4096; eltype::DataType=Float64, ntrials::Integer=3
end

if parallel
let Distributed = Base.require(Base.PkgId(
let Distributed = Base.require_stdlib(Base.PkgId(
Base.UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed"))
nworkers = @invokelatest Distributed.nworkers()
results = @invokelatest Distributed.pmap(peakflops, fill(n, nworkers))
Expand Down
22 changes: 10 additions & 12 deletions stdlib/REPL/src/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1188,25 +1188,23 @@ function setup_interface(
']' => function (s::MIState,o...)
if isempty(s) || position(LineEdit.buffer(s)) == 0
pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")
if Base.locate_package(pkgid) !== nothing # Only try load Pkg if we can find it
Pkg = Base.require(pkgid)
REPLExt = Base.get_extension(Pkg, :REPLExt)
# Pkg should have loaded its REPL mode by now, let's find it so we can transition to it.
pkg_mode = nothing
REPLExt = Base.require_stdlib(pkgid, "REPLExt")
pkg_mode = nothing
if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider)
for mode in repl.interface.modes
if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider
pkg_mode = mode
break
end
end
# TODO: Cache the `pkg_mode`?
if pkg_mode !== nothing
buf = copy(LineEdit.buffer(s))
transition(s, pkg_mode) do
LineEdit.state(s, pkg_mode).input_buffer = buf
end
return
end
# TODO: Cache the `pkg_mode`?
if pkg_mode !== nothing
buf = copy(LineEdit.buffer(s))
transition(s, pkg_mode) do
LineEdit.state(s, pkg_mode).input_buffer = buf
end
return
end
end
edit_insert(s, ']')
Expand Down
6 changes: 3 additions & 3 deletions test/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -407,11 +407,11 @@ precompile_test_harness(false) do dir
else
ocachefile = nothing
end
# use _require_from_serialized to ensure that the test fails if
# the module doesn't reload from the image:
# use _require_from_serialized to ensure that the test fails if
# the module doesn't reload from the image:
@test_warn "@ccallable was already defined for this method name" begin
@test_logs (:warn, "Replacing module `$Foo_module`") begin
m = Base._require_from_serialized(Base.PkgId(Foo), cachefile, ocachefile)
m = Base._require_from_serialized(Base.PkgId(Foo), cachefile, ocachefile, Foo_file)
@test isa(m, Module)
end
end
Expand Down

0 comments on commit ea1a0d2

Please sign in to comment.