Crystal: Invalid memory access (signal 11) at address 0x841f13

Created on 15 Dec 2019  路  9Comments  路  Source: crystal-lang/crystal

After a good while of debugging I finally was able to create a reproducible example of this issue.

https://play.crystal-lang.org/#/r/87at

class Obj
  property value : String? = nil
end

module Container
  class_property obj : Obj = Obj.new
end

struct RoutingController
  def initialize
    @store = Container.obj
  end

  def safe_request_check : String?
    @store.value
  end
end

class Route
  def initialize(@action : Proc(String?)); end

  def execute
    @action.call
  end
end

class RouteResolver
  def resolve
    cont = RoutingController.new

    Route.new(
      ->cont.safe_request_check,
    )
  end
end

obj = Container.obj

route = RouteResolver.new.resolve

obj.value = "foo"

pp route.execute
Invalid memory access (signal 11) at address 0x841f13
[0x55ab5bb42916] *CallStack::print_backtrace:Int32 +118
[0x55ab5bb349b1] __crystal_sigfault_handler +209
[0x7f4100450930] ???
[0x55ab5bb4b790] ???
[0x55ab5bb4eb62] *String#pretty_print<PrettyPrint>:Nil +434
[0x55ab5bb9b300] *PrettyPrint::format<(String | Nil), IO::FileDescriptor, Int32, String, Int32>:IO::FileDescriptor +208
[0x55ab5bb9b223] *PrettyPrint::format<(String | Nil), IO::FileDescriptor, Int32>:IO::FileDescriptor +67
[0x55ab5bb34a50] *pp<(String | Nil)>:(String | Nil) +32
[0x55ab5bb26a93] __crystal_main +1235
[0x55ab5bba1856] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6
[0x55ab5bba17b9] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +41
[0x55ab5bb31fa6] main +6
[0x7f4100218153] __libc_start_main +243
[0x55ab5bb264ee] _start +46
[0x0] ???

A few things to note:

  • Making the RoutingController a class makes it work
  • Making RouteResolver#resolve directly return the proc makes it work (example)
  • Removing the RouteResolver and directly setting the Route obj makes it work (example)

Most helpful comment

@jwoertink Are you using ->foo.bar things in your app?

In any case, I have a fix for this coming up soon.

All 9 comments

You have a dangling pointer: cont is allocated on the stack, the function returns, so the stack will be overwritten (which overwrite cont value) but you kept a reference in the proc, which is eventually called and crashes (dangling pointer).

RouteController can't be a struct, or must be allocated somewhere in the HEAP (as a class or global property for example) or just be a class.

I don't suppose there is anything that can be done; like a better error message or something? Otherwise I guess we can close as this is works as designed.

The bug is accessing a stack allocated variable from a captured block. By the time the block will be called, the stack variable won't exist anymore. I assume it could be catched. Same for returning a pointer to a stack allocated variable.

Just a note: the compiler notices when a variable is closures and it will keep a copy of it on the heap. The problem might be that it's a copy and not the actual value. But I don't know because I didn't dig into it yet.

Reduced:

struct Foo
  def initialize
    @value = Bytes.new(32)
  end

  def value
    puts("called (size: #{@value.size})")
    @value.to_unsafe.to_slice(32)
  end
end

def get_proc_a
  foo = Foo.new
  ->foo.value
end

def get_proc_b
  foo = Foo.new
  ->{ foo.value }
end

proc_a = get_proc_a
proc_b = get_proc_b
puts(proc_b.call.hexstring)
puts(proc_a.call.hexstring)
called (size: 32)
0000000000000000000000000000000000000000000000000000000000000000
called (size: -660869216)
0100000040000000400000003030303030303030303030303030303030303030

Using ->foo.value, will read random memory after the local foo moves out of scope.
->{ foo.value }, seems to properly closure the Foo instance so that it remains valid, as @asterite described.

I'm unfamiliar with how ->method works, but a segfault is the "best" case; you may end up reading a "valid", yet corrupted object. (i.e., @value : Int32, example)
Is a naive solution to rewrite ->method to ->{ method } in these situations..? Not entirely sure how you (the compiler) would make this safe.

Anyways, hope this helps :smile_cat:

This error is a super common error we see with Lucky when deploying. It's common that a new person trying out Lucky will go to deploy to a Docker container or to Heroku, and will see this error during deployment. Most of the time we tell them to clear heroku cache or prune their docker system and it's fine. However, I'm getting this on one of my apps, and I can't deploy at all. I've gone through the normal tricks and such, but I'm on deployment 7 now, and can't get past shards update --production --ignore-crystal-version.

Invalid memory access (signal 11) at address 0x7f924c776678
[0x7f9271e67f96] ???
[0x7f9271db1beb] ???
[0x7f9272c35831] ???

I'm not sure what changed exactly, but normally when I get this, a second deploy (or clearing the cache) will fix it and I move on. I wish I had code I could share, but it looks like there's a few examples above that might help? Or you could try building a simple app in Lucky and deploy to Heroku since that will usually cause the issue. I'm down to add in any sort of debugging or whatever will help this out.

Ok, after a bit of digging, it turns out the docker step it's stuck on is:

RUN shards update --production --ignore-crystal-version && \
    rm -rf /app/build/app && \
    crystal build -Dpreview_mt src/start_server.cr --release -o app

I don't remember adding that preview_mt, but I must have been testing something. I haven't deployed this app in a few months. I removed that flag, and it deployed just fine. Not sure if that helps at all, but for now I'm in the clear and won't be fired 馃槅

@jwoertink Are you using ->foo.bar things in your app?

In any case, I have a fix for this coming up soon.

I'm not directly, but it's possible there's some in Lucky itself somewhere.... But a fix would be amazing!!!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jhass picture jhass  路  3Comments

asterite picture asterite  路  3Comments

oprypin picture oprypin  路  3Comments

cjgajard picture cjgajard  路  3Comments

RX14 picture RX14  路  3Comments