ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:116814] [Ruby master Feature#20273] Disable callcc when compiled with ASAN
@ 2024-02-17  5:42 kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  2024-02-17 11:51 ` [ruby-core:116823] " mame (Yusuke Endoh) via ruby-core
  2024-02-18 23:16 ` [ruby-core:116832] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  0 siblings, 2 replies; 3+ messages in thread
From: kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core @ 2024-02-17  5:42 UTC (permalink / raw
  To: ruby-core; +Cc: kjtsanaktsidis (KJ Tsanaktsidis)

Issue #20273 has been reported by kjtsanaktsidis (KJ Tsanaktsidis).

----------------------------------------
Feature #20273: Disable callcc when compiled with ASAN
https://bugs.ruby-lang.org/issues/20273

* Author: kjtsanaktsidis (KJ Tsanaktsidis)
* Status: Open
* Priority: Normal
----------------------------------------
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.



-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [ruby-core:116823] [Ruby master Feature#20273] Disable callcc when compiled with ASAN
  2024-02-17  5:42 [ruby-core:116814] [Ruby master Feature#20273] Disable callcc when compiled with ASAN kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
@ 2024-02-17 11:51 ` mame (Yusuke Endoh) via ruby-core
  2024-02-18 23:16 ` [ruby-core:116832] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  1 sibling, 0 replies; 3+ messages in thread
From: mame (Yusuke Endoh) via ruby-core @ 2024-02-17 11:51 UTC (permalink / raw
  To: ruby-core; +Cc: mame (Yusuke Endoh)

Issue #20273 has been updated by mame (Yusuke Endoh).


I think it makes sense basically. I would like to see details in PR. Do you already have a patch?

----------------------------------------
Feature #20273: Disable callcc when compiled with ASAN
https://bugs.ruby-lang.org/issues/20273#change-106848

* Author: kjtsanaktsidis (KJ Tsanaktsidis)
* Status: Open
* Priority: Normal
----------------------------------------
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.



-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [ruby-core:116832] [Ruby master Feature#20273] Disable callcc when compiled with ASAN
  2024-02-17  5:42 [ruby-core:116814] [Ruby master Feature#20273] Disable callcc when compiled with ASAN kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  2024-02-17 11:51 ` [ruby-core:116823] " mame (Yusuke Endoh) via ruby-core
@ 2024-02-18 23:16 ` kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
  1 sibling, 0 replies; 3+ messages in thread
From: kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core @ 2024-02-18 23:16 UTC (permalink / raw
  To: ruby-core; +Cc: kjtsanaktsidis (KJ Tsanaktsidis)

Issue #20273 has been updated by kjtsanaktsidis (KJ Tsanaktsidis).


What about something like this? https://github.com/ruby/ruby/pull/10012

This is the "maximal" way - it adds a new define `RUBY_CALLCC_ENABLED`, which we set to on normally but off if asan is enabled. Then, all the callcc related code gets guarded by this macro (including the bits spread around in vm.c for example).

I can do something less invasive (like this? https://github.com/ruby/ruby/commit/b3500503478e81985ac8d95b3576135f9787bcf6) but that generates unused function warnings that would have to be suppressed (with some ignore_unused attributes or some such)

----------------------------------------
Feature #20273: Disable callcc when compiled with ASAN
https://bugs.ruby-lang.org/issues/20273#change-106857

* Author: kjtsanaktsidis (KJ Tsanaktsidis)
* Status: Open
* Priority: Normal
----------------------------------------
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.



-- 
https://bugs.ruby-lang.org/
 ______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-02-18 23:16 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-02-17  5:42 [ruby-core:116814] [Ruby master Feature#20273] Disable callcc when compiled with ASAN kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core
2024-02-17 11:51 ` [ruby-core:116823] " mame (Yusuke Endoh) via ruby-core
2024-02-18 23:16 ` [ruby-core:116832] " kjtsanaktsidis (KJ Tsanaktsidis) via ruby-core

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).