rubyjs / mini_racer

Minimal embedded v8
MIT License
594 stars 93 forks source link

mini_racer 0.12.0 Segmentation fault on x86_64-linux with libv8-node 21.7.2.0 #300

Closed D-system closed 1 month ago

D-system commented 5 months ago

Hello the team

Thank you for the update to libv8-node 21.7.2.0 yesterday. I wanted to report an error. Setup:

/home/circleci/ec/vendor/ruby/3.2.0/gems/mini_racer-0.12.0/lib/mini_racer.rb:228: [BUG] Segmentation fault at 0x00007f3f10a31008
ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0048 p:---- s:0301 e:000300 CFUNC  :eval_unsafe
c:0047 p:0009 s:0295 e:000294 BLOCK  /home/circleci/repo/vendor/ruby/3.2.0/gems/mini_racer-0.12.0/lib/mini_racer.rb:228
c:0046 p:0010 s:0292 e:000291 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/mini_racer-0.12.0/lib/mini_racer.rb:348
c:0045 p:0008 s:0281 e:000280 BLOCK  /home/circleci/repo/vendor/ruby/3.2.0/gems/mini_racer-0.12.0/lib/mini_racer.rb:227 [FINISH]
c:0044 p:---- s:0278 e:000277 CFUNC  :synchronize
c:0043 p:0045 s:0274 e:000273 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/mini_racer-0.12.0/lib/mini_racer.rb:225
c:0042 p:0007 s:0267 e:000266 BLOCK  /home/circleci/repo/vendor/ruby/3.2.0/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:11
c:0041 p:0003 s:0264 e:000262 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:67
c:0040 p:0035 s:0256 e:000255 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:10 [FINISH]
c:0039 p:---- s:0249 e:000248 CFUNC  :new
c:0038 p:0038 s:0242 e:000241 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/execjs-2.9.1/lib/execjs/runtime.rb:68
c:0037 p:0013 s:0236 e:000235 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/execjs-2.9.1/lib/execjs/module.rb:27
c:0036 p:0020 s:0230 e:000229 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/terser-1.2.2/lib/terser.rb:189
c:0035 p:0065 s:0223 e:000221 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/terser-1.2.2/lib/terser.rb:229
SEGV received in SEGV handler
c:0034 p:0014 s:0212 e:000211 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/terser-1.2.2/lib/terser.rb:181
c:0033 p:0029 s:0206 e:000205 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/terser-1.2.2/lib/terser/compressor.rb:36
c:0032 p:0007 s:0198 e:000197 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/terser-1.2.2/lib/terser/compressor.rb:23
c:0031 p:0047 s:0193 e:000192 METHOD /home/circleci/repo/vendor/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:84
c:0030 p:0013 s:0185 e:000184 BLOCK  /home/circleci/repo/vendor/ruby/3.2.0/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:66 [FINISH]
c:0029 p:---- s:0180 e:000179 CFUNC  :reverse_each
c:0028 p:0035 
Received "aborted" signal

It does work on Darwin Kernel Version 23.2.0 arm64 (Mac on arm) that compile from source.

The error is from eval -> eval_unsafe, so I suspect it is an issue with the libv8-node https://github.com/rubyjs/mini_racer/blob/5b2a25cdb4c84c7500ed47639ef8c664f5bac26d/lib/mini_racer.rb#L228

noctivityinc commented 4 months ago

@huda-kh what did you downgrade libv8-node to and did you do that by adding it directly to your gemfile?

noctivityinc commented 4 months ago

I can also confirm that downgrading to gem "mini_racer", "~> 0.9.0" # <- added so far seems to have fixed the issue

huda-kh commented 4 months ago

@huda-kh what did you downgrade libv8-node to and did you do that by adding it directly to your gemfile?

Yes, gem 'libv8-node', '~> 20.12.1'

project99 commented 4 months ago

the node version doesn't seems to be the cause of the crash for me

/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/mini_racer-0.6.3/lib/mini_racer.rb:183: [BUG] Segmentation fault at 0x0000000000000000 ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]

I'm also getting the above while setting up my local env on a different computer.

However, the strange thing is that the setup between the 2 machines are identical, as per below

mini_racer 0.6.3 libv8-node 16.10.0.0 Ruby 3.2.2 OS: Windows 11 WSL - Ubuntu 22.04.3 LTS Rails: 6.1.7.3 Sprockets: 3.7.2

when I run rails s everything works fine on my original machine but I'm getting the fault on my new machine.

Any ideas on where else to investigate?

SamSaffron commented 3 months ago

@cataphract did you have a chance to look at this?

SamSaffron commented 3 months ago

@lloeki FYI my above sample also repros outside of docker... it crashes with a segfault in the isolate->Dispose() line. I checked and the isolate is not in use, I guess the next step here is to compile this somehow on local with symbols so we can step into v8 and see where in Dispose this is crashing. will try a bit more to figure out if I can somehow make repro script, nothing complex is happening here just creating a context and then GC is clearing it up.

SamSaffron commented 3 months ago

Repro:

#!/usr/bin/env ruby

require "bundler/setup"
require "mini_racer"
Thread
  .new do
    ctx = MiniRacer::Context.new
    ctx.eval(File.read("/tmp/eval.js"))
  end
  .join

eval.js is eval.js.txt

lloeki commented 3 months ago

Fantastic, thank you Sam. I'll try again to repro, possibly sourcing some other hardware.

Long shot hunch but given the strange consistency of repro works vs crashes in near-identical software environments I'm wondering if there's some (real or virtual) hardware component related, e.g CPU. Maybe a total red herring, but who knows.

My CPUs are:

I'm also:

What are yours folks?

If you can e.g cat /proc/cpuinfo under Linux (native + inside WSL/Docker for Mac) and other CPU-Z or whatever output on Windows, or Mac exact CPU info...), and whatever you're using as some sort of virtualisation if so.

SamSaffron commented 3 months ago

I am on Intel(R) Core(TM) i9-14900K

It crashes consistently on dispose isolate and works consistently with 20.12.1.0

I need to figure out how to build on local to see if this is something about how we are building node

SamSaffron commented 3 months ago

@lloeki are there any concerns around downgrading mini_racer to 20.12.1.0 while we work out what is going on here?

lloeki commented 3 months ago

@SamSaffron thanks.

If you want a simple automated process, you can do:

# for whatever your current system is (Darwin on Darwin, Linux on Linux), resulting gem will be in `pkg` and the repo will also contain all intermediate build results so it's directly usable via `gem 'libv8-node, path:...`
# I highly recommend installing `ccache` beforehand to speed up rebuilds, which will be picked up and used automatically
make -f Makefile gem

# for building for Linux inside docker, picks up your current platform automatically and puts the result in `pkg`
# this automatically has `ccache` installed and leverages a `docker buildx` cache mount
make -f Makefile.docker gem

# you can also target a specific platform manually
make -f Makefile.docker pkg/libv8-node-21.7.2-aarch64-linux.gem
make -f Makefile.docker pkg/libv8-node-21.7.2-aarch64-linux-musl.gem
make -f Makefile.docker pkg/libv8-node-21.7.2-x86_64-linux.gem
make -f Makefile.docker pkg/libv8-node-21.7.2-x86_64-linux-musl.gem

If you want to do a fully manual build (feel free to hack build-libv8 to do a debug build and build-monolith to prevent stripping):

./libexec/download-node
./libexec/extract-node
./libexec/build-libv8
./libexec/build-monolith
./libexec/inject-libv8 # after this, repository is directly usable via `gem 'libv8-node, path:...`
bundle exec rake binary # optional, that's if you want to build a gem from the result

Then you can simply reference the repo as a path in a mini_racer's clone:

# in mini_racer's Gemfile

gem 'libv8-node', path: '../libv8-node'

Once it's built, do the usual mini_racer's bundle exec rake compile. Don't forget to bundle exec rake clean (although I usually do find . -name \( '*.bundle' -or -name '*.so' \) -delete; bundle exec rake clean because sometimes rake clean is not enough).

All of the libexec scripts can take an optional Node version as argument, e.g ./libexec/download-node 21.7.2, otherwise it defaults to picking up the version in lib/libv8/node/versions.rb for convenience.

(Note to myself: this above should go into the README.md or a DEVELOPMENT.md file)

lloeki commented 3 months ago

@SamSaffron I'm thinking of something: at some point I moved to using clang for Linux builds. Maybe it's related to the compiler and gcc would be fine.

This can be changed by removing clang in Dockerfile, then the build will fall back to using gcc:

diff --git a/Dockerfile b/Dockerfile
index f44ba8f..890bed0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,8 +1,8 @@
 ARG RUBY_VERSION=2.7
 FROM ruby:${RUBY_VERSION}

-RUN test ! -f /etc/alpine-release || apk add --no-cache build-base bash python3 git curl tar ccache clang
-RUN test -f /etc/alpine-release || (apt-get update && apt-get install -y ccache clang)
+RUN test ! -f /etc/alpine-release || apk add --no-cache build-base bash python3 git curl tar ccache
+RUN test -f /etc/alpine-release || (apt-get update && apt-get install -y ccache)
 ENV CCACHE_DIR=/ccache

 RUN gem update --system 3.3.26 && gem install bundler -v '~> 2.3.26'
SamSaffron commented 3 months ago

I feel we should probably be using GCC to match the toolset on https://github.com/nodejs/node/blob/main/BUILDING.md

looks like GCC 10 specifically.

I also wonder if we should be building inside RHEL8 to match the toolset of node for the binary?

SamSaffron commented 3 months ago

thanks so much for the instruction ... CPU is running hot now :)

lloeki commented 3 months ago

we should probably be using GCC to match the toolse

The intent behind the move was that it is so much easier to do cross-compiling with clang: you just have to have a proper sysroot and pass the -issyroot flag, whereas with GCC you have to build an actual set of cross-compilers for each target platform. That's why aarch64-linux-musl is not in the CI anymore: because there's none in Alpine's apk (but Debian provides some for GCC, hence why that one stayed).

I also wonder if we should be building inside RHEL8 to match the toolset of node for the binary?

Maybe manylinux instead then (which is CentOS based). That's significant work though. Let's try the compiler first.

Also @SamSaffron that makes me think, can you reproduce the issue with both glibc and musl or just glibc?

SamSaffron commented 3 months ago

I am on glibc here yeah lets see I am building now with gcc to see if it resolves before going too crazy.

SamSaffron commented 3 months ago

appears to still be crashing under GCC :( need to get more symbols cause this is not exactly helpful:

-- C level backtrace information -------------------------------------------
/home/sam/.rubies/ruby-3.2.3/bin/ruby(rb_print_backtrace+0x14) [0x607040e6163b] /home/sam/src/ruby-3.2.3/vm_dump.c:785
/home/sam/.rubies/ruby-3.2.3/bin/ruby(rb_vm_bugreport) /home/sam/src/ruby-3.2.3/vm_dump.c:1080
/home/sam/.rubies/ruby-3.2.3/bin/ruby(rb_bug_for_fatal_signal+0xe8) [0x607040fe0ed8] /home/sam/src/ruby-3.2.3/error.c:813
/home/sam/.rubies/ruby-3.2.3/bin/ruby(sigsegv+0x4b) [0x607040daa78b] /home/sam/src/ruby-3.2.3/signal.c:964
/usr/lib/libc.so.6(0x7e68fedf0ae0) [0x7e68fedf0ae0]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f77b8e1a) [0x7e68f77b8e1a]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f76c1497) [0x7e68f76c1497]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f76c15a8) [0x7e68f76c15a8]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f76c320b) [0x7e68f76c320b]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f76b2647) [0x7e68f76b2647]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f75f21eb) [0x7e68f75f21eb]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f7611ee7) [0x7e68f7611ee7]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f6d790fc) [0x7e68f6d790fc]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f6d7bab9) [0x7e68f6d7bab9]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f6b2abab) [0x7e68f6b2abab]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(0x7e68f6b2d371) [0x7e68f6b2d371]
/home/sam/Source/mini_racer/lib/mini_racer_extension.so(free_context_raw+0x133) [0x7e68f6b2ad65] ../../../../ext/mini_racer_extension/mini_racer_extension.cc:1471

I wish I could get a backtrace with the location in v8.

Also... maybe this goes away on 22.4 or 22.7.3 ... I doubt it but who knows?

SamSaffron commented 3 months ago

I have good news @lloeki

libv8-node-22.4.0.0-x86_64-linux.gem

No longer crashes, any chance you can push this out? This may be the best possible resolution here...

  1) Failure:
MiniRacerTest#test_timeout [test/mini_racer_test.rb:1045]:
MiniRacer::ScriptTerminatedError expected but nothing was raised.

I am sure this is resolvable...

lloeki commented 3 months ago

libv8-node-22.4.0.0-x86_64-linux.gem No longer crashes

Is that built with GCC?

This may be the best possible resolution here

Agreed. I'll do builds as soon as I can.

Failure: MiniRacerTest#test_timeout

I'll take that instead of a crasher any day. Also...

I am sure this is resolvable

test_timeout: timeout things are annoying, maybe it's just the test itself isn't quite correct / flaky. I also seem to vaguely recall overhearing there have been some annoyances/changes regarding timeouts.

SamSaffron commented 3 months ago

The test is no longer failing cause this returns immediately now

        var doit = async() => {
        while (true)
          await new Promise(resolve => resolve())
        }
        doit();

v8 must have a new optimisation here to work around this crazy

I think we can probably just comment this out.

It was built with GCC.

lloeki commented 3 months ago

v8 must have a new optimisation here to work around this crazy

Haha yeah, I've had to change another test because V8 started to optimise an invariant bit which completely elided out a certain execution that was expected in the text, so I had to trick into not being able to optimise it.

I might be able to do something here by making it do some actual but still fake work in a similar way.

It was built with GCC.

Good. I'l move back things to use GCC.

SamSaffron commented 3 months ago

Loic any chance you can push the new builds this coming week?

On Wed, 3 Jul 2024 at 10:44 AM, Loic Nageleisen @.***> wrote:

v8 must have a new optimisation here to work around this crazy

Haha yeah, I've had to change another test because V8 started to optimise an invariant bit which completely elided out a certain execution that was expected in the text, so I had to trick into not being able to optimise it.

I might be able to do something here by making it do some actual but still fake work in a similar way.

It was built with GCC.

Good. I'l move back things to use GCC.

— Reply to this email directly, view it on GitHub https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2205441573, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAABIXMOYUGY4TDDSFIJXGDZKO2YVAVCNFSM6AAAAABGUEE3QSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMBVGQ2DCNJXGM . You are receiving this because you were mentioned.Message ID: @.***>

lloeki commented 3 months ago

@SamSaffron Yeah I think I can fit that in this week's schedule.

tisba commented 3 months ago

@SamSaffron Yeah I think I can fit that in this week's schedule.

Let me know when you have the build, happy to put it through some testing.

SamSaffron commented 2 months ago

Loic, any chance? Maybe if this is too hard just commit a readme on how to publish the builds and I can figure out how to reassign ?

On Mon, 15 Jul 2024 at 8:08 AM, Sebastian Cohnen @.***> wrote:

@SamSaffron https://github.com/SamSaffron Yeah I think I can fit that in this week's schedule.

Let me know when you have the build, happy to put it through some testing.

— Reply to this email directly, view it on GitHub https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2227759703, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAABIXIQIANZZSFVOOVOWXTZMNRN5AVCNFSM6AAAAABGUEE3QSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMRXG42TSNZQGM . You are receiving this because you were mentioned.Message ID: @.***>

lloeki commented 2 months ago

@SamSaffron apologies for the lack of updates, I started building but hit some local snags. I should have them sorted out over the weekend.

lloeki commented 2 months ago

Building.

lloeki commented 2 months ago

Hitting this when building on ruby:2.7-alpine with GCC 11 (ruby:2.7 has gcc 10):

#19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc: In lambda function:
#19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc:8620:59: error: too many initializers for 'v8::internal::wasm::WrapperCompilationInfo::<unnamed union>'
#19 673.3  8620 |             .import_info = {kind, expected_arity, suspend}},
#19 673.3       |                                                           ^
#19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc: In function 'v8::internal::wasm::WasmCompilationResult v8::internal::compiler::CompileWasmImportCallWrapper(v8::internal::wasm::CompilationEnv*, v8::internal::wasm::ImportCallKind, const FunctionSig*, bool, int, v8::internal::wasm::Suspend)':
#19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc:8658:76: error: use of 'v8::internal::compiler::CompileWasmImportCallWrapper(v8::internal::wasm::CompilationEnv*, v8::internal::wasm::ImportCallKind, const FunctionSig*, bool, int, v8::internal::wasm::Suspend)::<lambda()>' before deduction of 'auto'
#19 673.3  8658 |   auto result = v8_flags.turboshaft_wasm_wrappers ? compile_with_turboshaft()
#19 673.3       |                                                     ~~~~~~~~~~~~~~~~~~~~~~~^~
#19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc: In lambda function:
#19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc:8782:63: error: too many initializers for 'v8::internal::wasm::WrapperCompilationInfo::<unnamed union>'
#19 673.3  8782 |                 .import_info = {kind, expected_arity, suspend}},
#19 673.3       |                                                               ^
#19 673.3 At global scope:
#19 673.3 cc1plus: note: unrecognized command-line option '-Wno-dangling-pointer' may have been intended to silence earlier diagnostics
#19 673.3 make: *** [tools/v8_gypfiles/v8_compiler.target.mk:336: /code/src/node-v22.5.1/out/Release/obj.target/v8_compiler/deps/v8/src/compiler/wasm-compiler.o] Error 1
#19 673.3 make: *** Waiting for unfinished jobs....
#19 678.8 rm eaa7c536ec54534ae0561a9a6eafe29ba9ba2b59.intermediate 8cd3d39129416144c03e73765e9ca10b3fba330e.intermediate
#19 678.8 make: Leaving directory '/code/src/node-v22.5.1/out'
#19 ERROR: process "/bin/sh -c ./libexec/build-libv8 ${NODE_VERSION}" did not complete successfully: exit code: 2

IIRC that's why I moved to clang.

SamSaffron commented 2 months ago

Clang vs gcc was not an issue from the earlier testing, gcc is theoretically better to match how node build stuff, but clang packs should work fine

On Mon, 22 Jul 2024 at 5:08 PM, Loic Nageleisen @.***> wrote:

Hitting this when building on ruby:2.7-alpine with GCC 11 (ruby:2.7 has gcc 10):

19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc: In lambda function:

19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc:8620:59: error: too many initializers for 'v8::internal::wasm::WrapperCompilationInfo::'

19 673.3 8620 | .import_info = {kind, expected_arity, suspend}},

19 673.3 | ^

19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc: In function 'v8::internal::wasm::WasmCompilationResult v8::internal::compiler::CompileWasmImportCallWrapper(v8::internal::wasm::CompilationEnv, v8::internal::wasm::ImportCallKind, const FunctionSig, bool, int, v8::internal::wasm::Suspend)':

19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc:8658:76: error: use of 'v8::internal::compiler::CompileWasmImportCallWrapper(v8::internal::wasm::CompilationEnv, v8::internal::wasm::ImportCallKind, const FunctionSig, bool, int, v8::internal::wasm::Suspend)::<lambda()>' before deduction of 'auto'

19 673.3 8658 | auto result = v8_flags.turboshaft_wasm_wrappers ? compile_with_turboshaft()

19 673.3 | ~~~~~~~^~

19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc: In lambda function:

19 673.3 ../deps/v8/src/compiler/wasm-compiler.cc:8782:63: error: too many initializers for 'v8::internal::wasm::WrapperCompilationInfo::'

19 673.3 8782 | .import_info = {kind, expected_arity, suspend}},

19 673.3 | ^

19 673.3 At global scope:

19 673.3 cc1plus: note: unrecognized command-line option '-Wno-dangling-pointer' may have been intended to silence earlier diagnostics

19 673.3 make: *** [tools/v8_gypfiles/v8_compiler.target.mk:336: /code/src/node-v22.5.1/out/Release/obj.target/v8_compiler/deps/v8/src/compiler/wasm-compiler.o] Error 1

19 673.3 make: *** Waiting for unfinished jobs....

19 678.8 rm eaa7c536ec54534ae0561a9a6eafe29ba9ba2b59.intermediate 8cd3d39129416144c03e73765e9ca10b3fba330e.intermediate

19 678.8 make: Leaving directory '/code/src/node-v22.5.1/out'

19 ERROR: process "/bin/sh -c ./libexec/build-libv8 ${NODE_VERSION}" did not complete successfully: exit code: 2

IIRC that's why I moved to clang.

— Reply to this email directly, view it on GitHub https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2243194362, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAABIXN2JHPFZS2F2OSNE33ZNUN6FAVCNFSM6AAAAABGUEE3QSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENBTGE4TIMZWGI . You are receiving this because you were mentioned.Message ID: @.***>

tisba commented 2 months ago

As a side node: Keep in mind, that Ruby 2.7 is EOL since 2023-03-31.

lloeki commented 2 months ago

Ruby 2.7 is EOL

It's not so much for the Ruby version than the glibc one.

lloeki commented 2 months ago

One platform left, should be done tomorrow.

lloeki commented 2 months ago

All built. Pushing.

lloeki commented 2 months ago

PR to bump dependency in mini_racer and prepare 0.13.0 release: https://github.com/rubyjs/mini_racer/pull/306

tisba commented 2 months ago

0.13.0 has been released.

@D-system: If you have a moment, could you check if the new version with upgraded Node fixes the issue for you?

D-system commented 2 months ago

@tisba I think you meant 0.13.0. Yes, I just tried with 0.13.0 without success. It still seg fault in the unsafe block.

#!/bin/bash -eo pipefail
RAILS_ENV=production SECRET_KEY_BASE=1 bin/rails assets:clobber assets:precompile
I, [2024-08-01T10:15:50.803867 #8314]  INFO -- : Removed /home/circleci/ec/public/assets
yarn install v1.22.19
warning package.json: No license field
info No lockfile found.
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
warning No license field
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 0.04s.
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:228: [BUG] Segmentation fault at 0x00007f9ca8fe03e8
ruby 3.3.4 (2024-07-09 revision be1089c8ec) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0045 p:---- s:0281 e:000280 CFUNC  :eval_unsafe
c:0044 p:0009 s:0275 e:000274 BLOCK  /home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:228
c:0043 p:0010 s:0272 e:000271 METHOD /home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:348
c:0042 p:0008 s:0261 e:000260 BLOCK  /home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:227 [FINISH]
c:0041 p:---- s:0258 e:000257 CFUNC  :synchronize
c:0040 p:0045 s:0254 e:000253 METHOD /home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:225
c:0039 p:0017 s:0247 e:000246 BLOCK  /home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:28
c:0038 p:0003 s:0244 e:000242 METHOD /home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:67
c:0037 p:0024 s:0236 e:000235 METHOD /home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:27
c:0036 p:0025 s:0230 e:000229 METHOD /home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:35
c:0035 p:0071 s:0224 e:000222 METHOD /home/circleci/.rubygems/gems/terser-1.2.3/lib/terser.rb:229
c:0034 p:0014 s:0213 e:000212 METHOD /home/circleci/.rubygems/gems/terser-1.2.3/lib/terser.rb:181
c:0033 p:0029 s:0207 e:000206 METHOD /home/circleci/.rubygems/gems/terser-1.2.3/lib/terser/compressor.rb:36
c:0032 p:0007 s:0199 e:000198 METHOD /home/circleci/.rubygems/gems/terser-1.2.3/lib/terser/compressor.rb:23
c:0031 p:0047 s:0194 e:000193 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:84
c:0030 p:0013 s:0186 e:000185 BLOCK  /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:66 [FINISH]
c:0029 p:---- s:0181 e:000180 CFUNC  :reverse_each
c:0028 p:0035 s:0177 e:000176 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:65
c:0027 p:0395 s:0169 e:000168 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:184
c:0026 p:0054 s:0145 e:000144 BLOCK  /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:59
c:0025 p:0033 s:0139 e:000138 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:339
c:0024 p:0115 s:0129 e:000128 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:43
c:0023 p:0006 s:0120 e:000119 BLOCK  /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/cached_environment.rb:44
c:0022 p:0013 s:0117 e:000114 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/map.rb:207
c:0021 p:0033 s:0112 e:000111 METHOD /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/map.rb:187
c:0020 p:0010 s:0105 e:000104 METHOD /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/map.rb:206
c:0019 p:0008 s:0099 e:000098 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/cached_environment.rb:44
c:0018 p:0025 s:0094 e:000093 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/base.rb:81
c:0017 p:0023 s:0086 e:000085 METHOD /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/base.rb:88 [FINISH]
c:0016 p:---- s:0075 e:000074 CFUNC  :each
c:0015 p:---- s:0072 e:000071 CFUNC  :to_a
c:0014 p:0009 s:0068 e:000067 BLOCK  /home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125
c:0013 p:0010 s:0065 e:000064 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb:24
c:0012 p:0002 s:0061 e:000060 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb:48 [FINISH]
c:0011 p:---- s:0058 e:000057 CFUNC  :synchronize
c:0010 p:0016 s:0054 e:000053 METHOD /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb:48
c:0009 p:0014 s:0050 e:000049 METHOD /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb:22
c:0008 p:0015 s:0042 e:000041 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/promise.rb:564
c:0007 p:0008 s:0036 e:000035 METHOD /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:359
c:0006 p:0041 s:0028 e:000027 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:350
c:0005 p:0018 s:0022 e:000021 METHOD <internal:kernel>:187
c:0004 p:0004 s:0017 e:000016 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341 [FINISH]
c:0003 p:---- s:0014 e:000013 CFUNC  :catch
c:0002 p:0006 s:0009 e:000008 BLOCK  /home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340 [FINISH]
c:0001 p:---- s:0003 e:000002 DUMMY  [FINISH]

-- Ruby level backtrace information ----------------------------------------
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `block in create_worker'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:340:in `catch'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:341:in `block (2 levels) in create_worker'
<internal:kernel>:187:in `loop'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:350:in `block (3 levels) in create_worker'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb:359:in `run_task'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/promise.rb:564:in `block in realize'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb:22:in `execute'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb:48:in `synchronize'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb:48:in `synchronize'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb:48:in `block in synchronize'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb:24:in `block in execute'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125:in `block (2 levels) in find'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125:in `to_a'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/manifest.rb:125:in `each'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/base.rb:88:in `find_all_linked_assets'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/base.rb:81:in `find_asset'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/cached_environment.rb:44:in `load'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/map.rb:206:in `fetch_or_store'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/map.rb:187:in `fetch'
/home/circleci/.rubygems/gems/concurrent-ruby-1.3.3/lib/concurrent-ruby/concurrent/map.rb:207:in `block in fetch_or_store'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/cached_environment.rb:44:in `block in load'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:43:in `load'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:339:in `fetch_asset_from_dependency_cache'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:59:in `block in load'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/loader.rb:184:in `load_from_unloaded'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:65:in `call_processors'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:65:in `reverse_each'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:66:in `block in call_processors'
/home/circleci/.rubygems/gems/sprockets-4.2.1/lib/sprockets/processor_utils.rb:84:in `call_processor'
/home/circleci/.rubygems/gems/terser-1.2.3/lib/terser/compressor.rb:23:in `call'
/home/circleci/.rubygems/gems/terser-1.2.3/lib/terser/compressor.rb:36:in `call'
/home/circleci/.rubygems/gems/terser-1.2.3/lib/terser.rb:181:in `compile_with_map'
/home/circleci/.rubygems/gems/terser-1.2.3/lib/terser.rb:229:in `run_terserjs'
/home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:35:in `call'
/home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:27:in `eval'
/home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:67:in `translate'
/home/circleci/.rubygems/gems/execjs-2.9.1/lib/execjs/mini_racer_runtime.rb:28:in `block in eval'
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:225:in `eval'
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:225:in `synchronize'
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:227:in `block in eval'
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:348:in `timeout'
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:228:in `block (2 levels) in eval'
/home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:228:in `eval_unsafe'

-- Threading information ---------------------------------------------------
Total ractor count: 1
Ruby thread count for this ractor: 38

-- Machine register context ------------------------------------------------
 RIP: 0x00007f9ca8fe0400 RBP: 0x00007f9d933f0620 RSP: 0x00007f9d933f0550
 RAX: 0x0000000000000003 RBX: 0x0000000000000000 RCX: 0x00007f9ca8fe0400
 RDX: 0x00000d18d2380069 RDI: 0x0000238071df0859 RSI: 0x0000238071de33f1
  R8: 0x0000000000000003  R9: 0x000000000000004f R10: 0x00007f9d5c2dcc99
 R11: 0x0000238071df085b R12: 0x0000238071df0859 R13: 0x00007f9d5c2c9080
 R14: 0x0000000000000003 R15: 0x00007f9d933f04c0 EFL: 0x0000000000010246

-- C level backtrace information -------------------------------------------

Received "segmentation fault" signal
SamSaffron commented 2 months ago

oh no, and yes we just saw some of these too cc @lloeki :cry:

will try debugging more this week

tisba commented 2 months ago

@SamSaffron you can still reproduce with https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2202876857?

Trying to reproduce with your example on GH Actions, in hopes this helps. So far without success 😞 https://github.com/tisba/mini_racer-issue-300/actions/runs/10193149124/job/28197243732#step:4:5

SamSaffron commented 2 months ago

Sadly https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2202876857 no longer crashes... I need a new consistent repro

SamSaffron commented 2 months ago

also https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2121759615 no longer crashes...

So I have no repro left here :(

SamSaffron commented 2 months ago

Hitting this when building on ruby:2.7-alpine with GCC 11 (ruby:2.7 has gcc 10):

Note @lloeki ... mini_racer no longer support any Ruby earlier than ruby 3.1. who knows maybe there are multiple issues here...

For starters though we need a consistent repro.

tisba commented 2 months ago

@D-system does https://github.com/rubyjs/mini_racer/issues/300#issuecomment-2121520163 still reproduce the issue for you?

SamSaffron commented 2 months ago

@lloeki I am trying here, but this is really hard for me due to poor background.

I can easily reproduce

c:0045 p:---- s:0281 e:000280 CFUNC  :eval_unsafe
c:0044 p:0009 s:0275 e:000274 BLOCK  /home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:228
c:0043 p:0010 s:0272 e:000271 METHOD /home/circleci/.rubygems/gems/mini_racer-0.13.0/lib/mini_racer.rb:348

On my local Discourse instance, just need to cook some markdown into html in a particular sequence. Trouble is I am yet to make a standalone program that will crash it.

Where I am super stuck now is figuring out how to get symbols going all the way through so I can get at least a full backtrace from v8 to have some clue of where v8 is crashing.

Will keep trying, but as it stands given the instability of these releases I am tempted to just do a new release that pins the version back to the version of v8 that works.

SamSaffron commented 2 months ago

I released 0.14 which now reverts the v8 upgrades. I really want to be on latest v8 but we can not yet, we need a stable release out there and that trumps wanting an upgrade :cry:

SamSaffron commented 2 months ago

Interesting datapoint @lloeki

Somewhere between 18.13 and 18.19 we broke test/test_forking.rb, it used to work fine, now it segfaults.

lloeki commented 2 months ago

Thanks folks for the unrelenting work in trying to reproduce! ❤️

mini_racer no longer support any Ruby earlier than ruby 3.1. who knows maybe there are multiple issues here...

By and large this doesn't matter, we could be building libv8 on a Rubyless image for all it cares. I plan to actually do that and move to something that makes having reproducible builds with better libc coverage (something like manylinux or even Nix).

Where I am super stuck now is figuring out how to get symbols going all the way through so I can get at least a full backtrace from v8 to have some clue of where v8 is crashing.

Super sorry I cannot help as it absolutely refuses to crash on any of my machines, whatever I throw at it :(

By the way the latest linux-gnu builds have been done with GCC.

Somewhere between 18.13 and 18.19 we broke test/test_forking.rb, it used to work fine, now it segfaults.

Huh, I didn't see that one, been running tests locally before pushing and they all passed (except the "libv8 now optimises the hell out of things" ones which are red herrings)

I released 0.14 which now reverts the v8 upgrades. I really want to be on latest v8 but we can not yet, we need a stable release out there and that trumps wanting an upgrade

At least this way:

lloeki commented 2 months ago

Note: rr has the ability to record execution and allows replaying execution even on totally foreign machines. Once someone gets debug symbols and records a crash, maybe that could help for me to get a hand on a replayable record.

SamSaffron commented 2 months ago

@lloeki do you get segfaults on local from test_forking?

Still struggling through this, I know how amazing it will be to have a nice standalone test that segfaults, it is just very hard to pin down.

SamSaffron commented 2 months ago

Well, I just built 12.7.224.15 from Source using the Google build toolchain.

Had to make some minor change to mini_racer:

--- a/ext/mini_racer_extension/mini_racer_extension.cc
+++ b/ext/mini_racer_extension/mini_racer_extension.cc
@@ -518,7 +518,7 @@ nogvl_context_eval(void* arg) {
     MaybeLocal<Script> parsed_script;

     if (eval_params->filename) {
-        origin = new v8::ScriptOrigin(isolate, *eval_params->filename);
+        origin = new v8::ScriptOrigin(*eval_params->filename);
     }

     parsed_script = Script::Compile(context, *eval_params->eval, origin);
@@ -791,7 +791,7 @@ static bool run_extra_code(Isolate *isolate, Local<v8::Context> context,
     }
     Local<String> resource_name =
             String::NewFromUtf8(isolate, name).ToLocalChecked();
-    ScriptOrigin origin(isolate, resource_name);
+    ScriptOrigin origin(resource_name);
     ScriptCompiler::Source source(source_string, origin);
     Local<Script> script;
     if (!ScriptCompiler::Compile(context, &source).ToLocal(&script))
@@ -954,9 +954,12 @@ static VALUE rb_isolate_idle_notification(VALUE self, VALUE idle_time_in_ms) {

     if (current_platform == NULL) return Qfalse;

-    double duration = NUM2DBL(idle_time_in_ms) / 1000.0;
-    double now = current_platform->MonotonicallyIncreasingTime();
-    return isolate_info->isolate->IdleNotificationDeadline(now + duration) ? Qtrue : Qfalse;
+    //double duration = NUM2DBL(idle_time_in_ms) / 1000.0;
+    //double now = current_platform->MonotonicallyIncreasingTime();
+    //return isolate_info->isolate->IdleNotificationDeadline(now + duration) ? Qtrue : Qfalse;
+
+    isolate_info->isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kModerate);
+    return Qtrue;
 }

And now the test that was crashing with the forking is working perfectly.

I enabled pointer compression and c++20 which is now required.

I am not sure I am trusting this node build anymore for our purpose. Will see if I can double test this on build as well. I had some trouble building though cause finding the right toolchain for older builds is a bit more tricky... will see what I can do.

We need to get test/test_forking.rb working as a #1 priority. This appears to be the canary in the coalmine.

SamSaffron commented 2 months ago

@lloeki my branch here builds v8 from source

https://github.com/rubyjs/mini_racer/blob/f134478987e9507d9a5ee7d7c2f75eb349657bb4/Rakefile#L31-L39

This build works just fine both with localization AND with the test_forking that was failing before.

So I suspect something about the way this node build is working is ending up with a corrupt ICU setup which is leading to the various faults.