Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a warning against having multiple copies of a shared library loaded #43007

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,15 @@ include("missing.jl")
# version
include("version.jl")

# Logging
include("logging.jl")
using .CoreLogging

# system & environment
include("sysinfo.jl")
include("libc.jl")
using .Libc: getpid, gethostname, time

# Logging
include("logging.jl")
using .CoreLogging

# Concurrency
include("linked_list.jl")
include("condition.jl")
Expand Down
56 changes: 54 additions & 2 deletions base/libdl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Base.DL_LOAD_PATH

export DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL,
RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW, dlclose, dlopen, dlopen_e, dlsym, dlsym_e,
dlpath, find_library, dlext, dllist
dlpath, find_library, dlext, dllist, check_dllist

"""
DL_LOAD_PATH
Expand Down Expand Up @@ -76,6 +76,57 @@ function dlsym_e(hnd::Ptr, s::Union{Symbol,AbstractString})
return something(dlsym(hnd, s; throw_error=false), C_NULL)
end

if Sys.isapple()
const dlpattern = r"^([^.]+).*\.dylib$"
elseif Sys.iswindows()
const dlpattern = r"^(.+)\.dll$"
else
#assume Sys.islinux, or similar
const dlpattern = r"^(.+?)\.so(?:\..*)?$"
end

const _dlname_cache = Dict{String, SubString{String}}()
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not thread-safe and goes against #41602

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you for the comment; it should be thread-safe now (without a performance regression).


"""
dlname(fullpath::String)

Returns the name of the library.
"""
function dlname(fullpath::String)::SubString{String}
cache = get(_dlname_cache, fullpath, "")
cache != "" && return cache
bn = basename(fullpath)
m = match(dlpattern, bn)
ret = isnothing(m) ? bn : m.captures[1]
_dlname_cache[fullpath] = ret
return ret
end

"""
check_dllist()

Check wheather the same shared library is loaded from two different files.
The `warnings` determines if the warnings are printed to the console.
"""
function check_dllist()
fullpaths = dllist()
names = dlname.(fullpaths)
perm = sortperm(names)
dlabspath(x) = isfile(x) ? abspath(realpath(x)) : x
for i in 1:length(names)-1
p1, p2 = perm[i], perm[i+1]
if names[p1] == names[p2]
if dlabspath(fullpaths[p1]) == dlabspath(fullpaths[p2])
continue
end
@warn """Detected possible duplicate library loaded: $(names[p1])
This may lead to unexpected behavior!
$(fullpaths[p1])
$(fullpaths[p2])""" maxlog=1
end
end
end

"""
dlopen(libfile::AbstractString [, flags::Integer]; throw_error:Bool = true)

Expand Down Expand Up @@ -113,11 +164,12 @@ function dlopen end
dlopen(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; kwargs...) =
dlopen(string(s), flags; kwargs...)

function dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; throw_error::Bool = true)
function dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND; throw_error::Bool = true, warnings::Bool = true)
ret = ccall(:jl_load_dynamic_library, Ptr{Cvoid}, (Cstring,UInt32,Cint), s, flags, Cint(throw_error))
if ret == C_NULL
return nothing
end
warnings && check_dllist()
return ret
end

Expand Down
4 changes: 2 additions & 2 deletions stdlib/Libdl/src/Libdl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module Libdl
# Just re-export Base.Libc.Libdl:
export DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL,
RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW, dlclose, dlopen, dlopen_e, dlsym, dlsym_e,
dlpath, find_library, dlext, dllist
dlpath, find_library, dlext, dllist, check_dllist

import Base.Libc.Libdl: DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL,
RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW, dlclose, dlopen, dlopen_e, dlsym, dlsym_e,
dlpath, find_library, dlext, dllist
dlpath, find_library, dlext, dllist, check_dllist

end # module