Skip to content

Commit

Permalink
[Products] Don't dlopen libraries built for an incompatible ISA
Browse files Browse the repository at this point in the history
  • Loading branch information
giordano committed Mar 24, 2022
1 parent 55c795d commit 7badc10
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "BinaryBuilderBase"
uuid = "7f725544-6523-48cd-82d1-3fa08ff4056e"
authors = ["Elliot Saba <staticfloat@gmail.com>"]
version = "1.8.0"
version = "1.8.1"

[deps]
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
Expand Down
2 changes: 1 addition & 1 deletion src/Products.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ function locate(lp::LibraryProduct, prefix::Prefix; platform::AbstractPlatform =
end

# If it does, try to `dlopen()` it if the current platform is good
if (!lp.dont_dlopen && !skip_dlopen) && platforms_match(platform, HostPlatform())
if (!lp.dont_dlopen && !skip_dlopen) && platforms_match(platform, augment_microarchitecture!(HostPlatform()))
if isolate
# Isolated dlopen is a lot slower, but safer
if success(`$(Base.julia_cmd()) --startup-file=no -e "import Libdl; Libdl.dlopen(\"$dl_path\")"`)
Expand Down
48 changes: 48 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# The functions in this file may not be used anywhere in this package but may
# needed by different modules of BinaryBuilder.jl

using Base.BinaryPlatforms: arch_march_isa_mapping, set_compare_strategy!
using Base.BinaryPlatforms.CPUID

with_logfile(f::Function, prefix::Prefix, name::String; subdir="") = with_logfile(f, joinpath(logdir(prefix; subdir), name))
function with_logfile(f::Function, logfile::String)
mkpath(dirname(logfile))
Expand Down Expand Up @@ -60,3 +63,48 @@ end
# We want the AnyPlatform to look like `default_host_platform`,
get_concrete_platform(::AnyPlatform, shards::Vector{CompilerShard}) =
get_concrete_platform(default_host_platform, shards)

function march_comparison_strategy(a::String, b::String, a_requested::Bool, b_requested::Bool)
# If both b and a requested, then we fall back to equality:
if a_requested && b_requested
return a == b
end

function get_arch_isa(isa_name::String)
for (arch, isas) in arch_march_isa_mapping
for (name, isa) in isas
name == isa_name && return arch, isa
end
end
return nothing, nothing
end

a_arch, a_isa = get_arch_isa(a)
b_arch, b_isa = get_arch_isa(b)
if any(isnothing, (a_arch, b_arch)) || a_arch != b_arch
# Architectures are definitely not compatible, exit early
return false
end

if a_requested
# ISA `b` is compatible with ISA `a` only if it's a subset of `a`
return b_isa a_isa
else
# ISA `a` is compatible with ISA `b` only if it's a subset of `b`
return a_isa b_isa
end
end

function augment_microarchitecture!(platform::Platform)
if haskey(platform, "march")
set_compare_strategy!(platform, "march", march_comparison_strategy)
return platform
end

host_arch = arch(HostPlatform())
host_isas = arch_march_isa_mapping[host_arch]
idx = findlast(((name, isa),) -> isa <= CPUID.cpu_isa(), host_isas)
platform["march"] = first(host_isas[idx])
set_compare_strategy!(platform, "march", march_comparison_strategy)
return platform
end
41 changes: 41 additions & 0 deletions test/compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,44 @@ using BinaryBuilderBase: download_verify, list_tarball_files
end
end
end

using BinaryBuilderBase: march_comparison_strategy
using Base.BinaryPlatforms: Platform, platforms_match, set_compare_strategy!
@testset "Microarchitecture augmentation" begin
linux_x86_64 = Platform("x86_64", "linux")
linux_avx = Platform("x86_64", "linux"; march="avx")
linux_avx2 = Platform("x86_64", "linux"; march="avx2")
linux_avx512 = Platform("x86_64", "linux"; march="avx512")
# Platform with non-existing microarchitecture
linux_bad = Platform("x86_64", "linux"; march="bad")

# Without any custom comparison strategy, the base platform without march matches
# everything, but the others are all incompatible
@test platforms_match(linux_x86_64, linux_avx)
@test platforms_match(linux_x86_64, linux_avx2)
@test platforms_match(linux_x86_64, linux_avx512)
@test platforms_match(linux_x86_64, linux_bad)
@test !platforms_match(linux_avx, linux_avx2)
@test !platforms_match(linux_avx, linux_avx512)
@test !platforms_match(linux_avx, linux_bad)
@test !platforms_match(linux_avx2, linux_bad)
@test !platforms_match(linux_avx2, linux_avx512)
@test !platforms_match(linux_avx512, linux_bad)

# Teach AVX2 platform how to compare the others
set_compare_strategy!(linux_avx2, "march", march_comparison_strategy)
for compatible_p in (linux_x86_64, linux_avx)
@test platforms_match(compatible_p, linux_avx2)
@test platforms_match(linux_avx2, compatible_p)
end
for incompatible_p in (linux_avx512, linux_bad)
@test !platforms_match(incompatible_p, linux_avx2)
@test !platforms_match(linux_avx2, incompatible_p)
end

# Teach also AVX platform how to compare
set_compare_strategy!(linux_avx, "march", march_comparison_strategy)
# Now when we compare AVX and AVX2, they must be equal
@test !platforms_match(linux_avx, linux_avx2)
@test !platforms_match(linux_avx2, linux_avx)
end

0 comments on commit 7badc10

Please sign in to comment.