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

Illegal instruction crash on 1.7 #44921

Closed
Octogonapus opened this issue Apr 9, 2022 · 6 comments · Fixed by #44942
Closed

Illegal instruction crash on 1.7 #44921

Octogonapus opened this issue Apr 9, 2022 · 6 comments · Fixed by #44942
Labels

Comments

@Octogonapus
Copy link
Contributor

Octogonapus commented Apr 9, 2022

I experienced a crash due to signal (4): Illegal instruction:

Unreachable reached at 0x7f91eb7569e5

signal (4): Illegal instruction
in expression starting at /home/salmon/Documents/code/YetAnotherTestFramework/test/v2/order_trait_test.jl:37
OrderTrait at /home/salmon/Documents/code/YetAnotherTestFramework/src/v2/executor/parse_time_trait.jl:68
unknown function (ip: 0x7f91e7f235cf)
Allocations: 8889567 (Pool: 8885928; Big: 3639); GC: 11

I have uploaded an rr trace of this crash here.

versioninfo:

Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)
Environment:
  JULIA_PKG_SERVER = 
  JULIA_EDITOR = code --wait

This also happens on the latest commit

Julia Version 1.9.0-DEV.353
Commit 73c9863087 (2022-04-09 15:06 UTC)
@Octogonapus
Copy link
Contributor Author

@ViralBShah ViralBShah added the system:linux Affects only Linux label Apr 10, 2022
@Octogonapus
Copy link
Contributor Author

Octogonapus commented Apr 10, 2022

This is the smallest MWE I can come up with.

module Foo

Base.@kwdef struct Options
    order::Symbol = :declared
    addprocs_machines = []
    addprocs_kwargs = []
end

abstract type ExecutionTreeNode end

const AllExecutionTreeNodeTypes = Union{ExecutionTreeNode,LineNumberNode}

struct Inner <: ExecutionTreeNode
    test_options::Options
end

struct Outer{T<:AllExecutionTreeNodeTypes}
    data::T
    children::Vector
end

abstract type TestNodeTrait end
struct IsKnownAtParseTime{T<:TestNodeTrait}
    trait::T
end
struct IsUnknownAtParseTime{T<:TestNodeTrait}
    trait::T
end
struct OrderTrait end
struct DeclaredOrder <: TestNodeTrait end
struct NumberedOrder <: TestNodeTrait end
struct ProcessParallelOrder <: TestNodeTrait end

function OrderTrait(tree)
    options = tree.data.test_options
    return if options.order == :declared
        IsKnownAtParseTime(DeclaredOrder())
    elseif options.order == :numbered
        IsKnownAtParseTime(NumberedOrder())
    elseif options.order == :process_parallel
        resolve_trait(tree, ProcessParallelOrder, [:addprocs_machines, :addprocs_kwargs])
    else
        error("")
    end
end

function resolve_trait(tree, trait_type, fields)
    return if options_unknown_at_parse_time(tree, fields)
        IsUnknownAtParseTime(trait_type())
    else
        IsKnownAtParseTime(trait_type())
    end
end

function options_unknown_at_parse_time(tree, fields)
    options = tree.data.test_options
    any_unknown = any(field -> pred(getproperty(options, field)), fields)
    return any_unknown
end

pred(it) = it isa Expr

end

import Test
Test.@testset "foo" begin
    Test.@test Foo.IsKnownAtParseTime(Foo.ProcessParallelOrder()) ==
               Foo.OrderTrait(Foo.Outer(Foo.Inner(Foo.Options(order = :process_parallel)), []))
end
╰─ julia Foo.jl        
Unreachable reached at 0x7f16039e7f9d

signal (4): Illegal instruction
in expression starting at /home/salmon/Documents/code/YetAnotherTestFramework/Foo.jl:66
OrderTrait at /home/salmon/Documents/code/YetAnotherTestFramework/Foo.jl:41
unknown function (ip: 0x7fff21917a2f)
Allocations: 663739 (Pool: 663280; Big: 459); GC: 1
[1]    33684 illegal hardware instruction  julia Foo.jl

This is an interesting example. You can get this code to produce other illegal instruction crashes by tweaking it; the type parameters on the structs are particularly effective. You can also fix the crashes by making other small changes. Try reducing the number of branches in the conditionals inside the OrderTrait function. Any less and the crash is gone. Remove the else and the crash is gone. Tweaking the functions that resolve_trait calls also works (maybe because of optimization?). If pred or options_unknown_at_parse_time simply return a boolean, the crash is gone.

@maleadt
Copy link
Member

maleadt commented Apr 11, 2022

Reduced to:

struct a{b}
    c::b
end
function d(e)
    if e == :x
        a(f)
    elseif e == :p
        g(e)
    end
end
function g(e)
    if !any([])
        a(())
    end
end
d(:p)

@giordano
Copy link
Contributor

giordano commented Apr 11, 2022

@maleadt what's f in your reduced example?

Edit: ok, it's undefined, I guess that's kinda part of the reproducer.

@gbaraldi
Copy link
Member

gbaraldi commented Apr 11, 2022

This happens on macos too. it crashes on x86 and hangs on m1. It hangs on jl_apply which kind of makes sense.

@vtjnash
Copy link
Member

vtjnash commented Apr 11, 2022

We added a Vboxed field, but forgot to set it, causing us to drop the boxv variable on the floor when converting Union{a{Tuple{}}, Nothing} (ghost union) to Union{a, Nothing} (partial-box union) as the return value. Just needs a test case to complete the fix here:

diff --git a/src/codegen.cpp b/src/codegen.cpp
index 7bd2be612e..85051b501a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1867,14 +1867,15 @@ static jl_cgval_t convert_julia_type_union(jl_codectx_t &ctx, const jl_cgval_t &
                 boxv = ctx.builder.CreateSelect(
                     ctx.builder.CreateAnd(wasboxed, isboxed), v.Vboxed, boxv);
             }
+            Value *slotv;
+            MDNode *tbaa;
             if (v.V == NULL) {
                 // v.V might be NULL if it was all ghost objects before
-                return jl_cgval_t(boxv, NULL, false, typ, new_tindex, ctx.tbaa());
+                slotv = NULL;
+                tbaa = ctx.tbaa().tbaa_const;
             }
             else {
                 Value *isboxv = ctx.builder.CreateIsNotNull(boxv);
-                Value *slotv;
-                MDNode *tbaa;
                 if (v.ispointer()) {
                     slotv = v.V;
                     tbaa = v.tbaa;
@@ -1887,12 +1888,12 @@ static jl_cgval_t convert_julia_type_union(jl_codectx_t &ctx, const jl_cgval_t &
                 slotv = ctx.builder.CreateSelect(isboxv,
                             decay_derived(ctx, boxv),
                             decay_derived(ctx, emit_bitcast(ctx, slotv, boxv->getType())));
-                jl_cgval_t newv = jl_cgval_t(slotv, NULL, false, typ, new_tindex, ctx.tbaa());
-                assert(boxv->getType() == ctx.types().T_prjlvalue);
-                newv.Vboxed = boxv;
-                newv.tbaa = tbaa;
-                return newv;
             }
+            jl_cgval_t newv = jl_cgval_t(slotv, NULL, false, typ, new_tindex, ctx.tbaa());
+            assert(boxv->getType() == ctx.types().T_prjlvalue);
+            newv.Vboxed = boxv;
+            newv.tbaa = tbaa;
+            return newv;
         }
     }
     else {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants