Project

General

Profile

Actions

Feature #20273

closed

Disable callcc when compiled with ASAN

Added by kjtsanaktsidis (KJ Tsanaktsidis) 3 months ago. Updated 3 months ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:116814]

Description

Currently, all of the callcc related tests in the Ruby test suite fail when Ruby is compiled with ASAN (CFLAGS="-fsanitize=address").

Unfortunately, I don't believe it's possible for calcc to be supported with ASAN at all. callcc is implemented by:

  • When saving a continuation, we take a copy of C the stack, and a jmpbuf with setjmp.
  • When calling a continuation, we memcpy the C stack back from the saved copy (using alloca to move the current top-of-stack out of the way of this copying), and then longjmp'ing back to the saved state

There are a few reasons this can't work with ASAN - some fixable, some not:

  • The copying of the original stack when creating a continuation requires reading stack memory from outside the current function, which ASAN does not allow (and, likewise with copying the stack back). This can be fixed by using a custom memcpy implementation which has __attribute__((no_sanitize("address"))).
  • When we restore the original stack, we also need to restore the shadow-words for that memory range (which record the state of what memory is and is not valid according to ASAN). ASAN does not expose a pointer to the shadow stack to allow it to be copied like this, but this is in theory something which we could patch in LLVM if we wanted to.
  • With ASAN, many local variables are not actually on the stack - rather, they're stored in a special "fake stack" (i think to enable detecting cases of stack-use-after-return). (I think) ASAN essentially malloc's memory for each function frame to hold these fake values, and frees them when the function returns. With callcc, some functions whose fake frames have already been freed might be re-entered, but the "fake stack" holding their local variables will have been freed. I don't believe there's a way to fix this that I can think of.

Therefore, I propose that:

  • When cruby is compiled with -fsanitize=address in CFLAGS, Kernel#callcc is rb_f_notimplement.
  • That means Kernel#respond_to?(:callcc) == false, and Kernel#callcc raises NotImplementedError
  • Tests in the cruby test suite which use callcc check respond_to?(:callcc) and skip themselves if so.

Since callcc is deprecated and meant only to be used for... um... "fun" things (https://bugs.ruby-lang.org/issues/10548), I think this is an acceptable tradeoff.


Related issues 1 (1 open0 closed)

Related to Ruby master - Misc #20387: Meta-ticket for ASAN supportAssignedkjtsanaktsidis (KJ Tsanaktsidis)Actions
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0