couchdb icon indicating copy to clipboard operation
couchdb copied to clipboard

feat: Add support for SpiderMonkey v140

Open big-r81 opened this issue 3 months ago • 5 comments

Tried to add SM v140. There are again some internal SpiderMonkey API changes.

Tried to compile against SpiderMonkey v140 and got following errors:

==> couch (compile)
Compiling /Users/big-r/Documents/Developer/CouchDB/couchdb/src/couch/priv/couch_js/140/main.cpp
In file included from /Users/big-r/Documents/Developer/CouchDB/couchdb/src/couch/priv/couch_js/140/main.cpp:24:
In file included from /usr/local/include/mozjs-140/jsapi.h:30:
In file included from /usr/local/include/mozjs-140/js/CallAndConstruct.h:15:
/usr/local/include/mozjs-140/js/RootingAPI.h:1169:34: warning: unknown warning group '-Wdangling-pointer', ignored [-Wunknown-warning-option]
 1169 | #  pragma GCC diagnostic ignored "-Wdangling-pointer"
      |                                  ^
/Users/big-r/Documents/Developer/CouchDB/couchdb/src/couch/priv/couch_js/140/main.cpp:241:5: error: cannot initialize a member subobject of type 'JSCSPEvalChecker' (aka 'bool (*)(JSContext *, JS::RuntimeCode, JS::Handle<JSString *>, JS::CompilationType, JS::Handle<JS::StackGCVector<JSString *>>, JS::Handle<JSString *>, JS::Handle<JS::StackGCVector<JS::Value>>, JS::Handle<JS::Value>, bool *)') with an lvalue of type 'bool (JSContext *, JS::RuntimeCode, JS::HandleString)' (aka 'bool (JSContext *, JS::RuntimeCode, Handle<JSString *>)'): different number of parameters (9 vs 3)
  241 |     csp_allows,
      |     ^~~~~~~~~~
1 warning and 1 error generated.
ERROR: compile failed while processing /Users/big-r/Documents/Developer/CouchDB/couchdb/src/couch: rebar_abort
make: *** [couch] Error 1

I changed the csp_allow method signature to fit the typedef in js/public/Principals.h. I don't know if there is a better solution.

Before:

static bool
csp_allows(JSContext* cx, JS::RuntimeCode kind, JS::HandleString code)
{
    couch_args* args = static_cast<couch_args*>(JS_GetContextPrivate(cx));
    if(args->eval) {
        return true;
    } else {
        return false;
    }
}


static JSSecurityCallbacks security_callbacks = {
    csp_allows,
    nullptr
};

After:

static bool
csp_allows(JSContext* cx,
    JS::RuntimeCode kind, JS::Handle<JSString*> codeString,
    JS::CompilationType compilationType,
    JS::Handle<JS::StackGCVector<JSString*>> parameterStrings,
    JS::Handle<JSString*> bodyString,
    JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs,
    JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings)
{
    couch_args* args = static_cast<couch_args*>(JS_GetContextPrivate(cx));
    if(args->eval) {
        return true;
    } else {
        return false;
    }
}


static JSSecurityCallbacks security_callbacks = {
    csp_allows,     //JSCSPEvalChecker contentSecurityPolicyAllows;
    nullptr,        //JSCodeForEvalOp codeForEvalGets;
    nullptr         //JSSubsumesOp subsumes;
};

Here are some additional infos what changed in SpiderMonkey from 128 -> 140.

big-r81 avatar Sep 25 '25 19:09 big-r81

The “problem” is, it’s not active in any CI run yet, so the tests are misleading 😉. I tried it with macOS, but got some errors (don’t know if it has todo with SpiderMonkey) …

big-r81 avatar Sep 28 '25 21:09 big-r81

Oops, @big-r81, good point. Maybe we can kick the macos runner again and see it can run with the latest 140.

If there are compilation errors, then I retract my +1

nickva avatar Sep 29 '25 04:09 nickva

Compilation is fine, there were two Elixir errors, one UTF-8 test and the other I don’t remember. Will paste it here. But maybe it’s good to test this by others…

big-r81 avatar Sep 29 '25 05:09 big-r81

These Elixir test fail:

ViewSandboxingTest [test/elixir/test/view_sandboxing_test.exs]
  * test view cannot invoke interpreter internals (83.2ms) [L#38]
  * test view cannot access the map_funs and map_results array (98.0ms) [L#56]
  * test COUCHDB-925 - altering 'doc' variable in map function affects other map functions (83.0ms) [L#82]
  * test runtime code evaluation can be prevented (54.4ms) [L#177]

  1) test runtime code evaluation can be prevented (ViewSandboxingTest)
     test/elixir/test/view_sandboxing_test.exs:177
     Assertion with == failed
     code:  assert resp.status_code == 200
     left:  500
     right: 200
     stacktrace:
       (couchdbtest 0.1.0) test/elixir/lib/couch/dbtest.ex:296: Couch.DBTest.query/6
       test/elixir/test/view_sandboxing_test.exs:188: (test)
UTF8Test [test/elixir/test/utf8_test.exs]
  * test UTF8 support (72.5ms) [L#12]

  2) test UTF8 support (UTF8Test)
     test/elixir/test/utf8_test.exs:12
     Assertion with in failed
     code:  assert status in [201, 202]
     left:  400
     right: [201, 202]
     stacktrace:
       (elixir 1.18.4) lib/enum.ex:987: Enum."-each/2-lists^foreach/1-0-"/2
       test/elixir/test/utf8_test.exs:25: (test)

Failed EUnit tests (idk if it has something todo with SM140):

module 'couch_bt_engine_cache_test'
  couch_bt_engine_cache_test:23: -couch_bt_engine_cache_test_/0-fun-6- (t_created)...ok
  couch_bt_engine_cache_test:24: -couch_bt_engine_cache_test_/0-fun-4- (t_insert_and_lookup)...*failed*
in function couch_bt_engine_cache_test:t_insert_and_lookup/1 (test/eunit/couch_bt_engine_cache_test.erl, line 73)
in call from eunit_test:run_testfun/1 (eunit_test.erl, line 83)
in call from eunit_proc:run_test/1 (eunit_proc.erl, line 554)
in call from eunit_proc:with_timeout/3 (eunit_proc.erl, line 379)
in call from eunit_proc:handle_test/2 (eunit_proc.erl, line 537)
in call from eunit_proc:tests_inorder/3 (eunit_proc.erl, line 479)
in call from eunit_proc:with_timeout/3 (eunit_proc.erl, line 369)
in call from eunit_proc:run_group/2 (eunit_proc.erl, line 593)
**error:{assert,[{module,couch_bt_engine_cache_test},
         {line,73},
         {expression,"couch_bt_engine_cache : insert ( { pid , 42 } , term )"},
         {expected,false},
         {value,true}]}
  output:<<"">>
    cpse_test_purge_docs
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_simple)...[0.003 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_simple_info_check)...[0.003 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_empty_db)...[0.001 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_single_docid)...[0.004 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_multiple_docids)...[0.004 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_no_docids)...[0.002 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_rev_path)...[0.005 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_deep_revision_path)...[0.241 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_partial_revs)...*failed*
in function couch_util:json_decode/2 (src/couch_util.erl, line 486)
in call from cpse_util:'-save_docs/3-fun-0-'/1 (src/cpse_util.erl, line 128)
in call from lists:map/2 (lists.erl, line 2385)
in call from cpse_util:save_docs/3 (src/cpse_util.erl, line 126)
in call from cpse_test_purge_docs:cpse_purge_partial_revs/1 (src/cpse_test_purge_docs.erl, line 253)
in call from eunit_test:run_testfun/1 (eunit_test.erl, line 83)
in call from eunit_proc:run_test/1 (eunit_proc.erl, line 554)
in call from eunit_proc:with_timeout/3 (eunit_proc.erl, line 379)
**throw:{invalid_json,{55,invalid_string}}
  output:<<"">>
    cpse_test_purge_seqs
      cpse_gather: -make_test_fun/3-fun-2- (cpse_increment_purge_seq_on_complete_purge)...[0.007 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_increment_purge_multiple_times)...[0.005 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_increment_purge_seq_on_partial_purge)...*failed*
in function couch_util:json_decode/2 (src/couch_util.erl, line 486)
in call from cpse_util:'-save_docs/3-fun-0-'/1 (src/cpse_util.erl, line 128)
in call from lists:map/2 (lists.erl, line 2385)
in call from cpse_util:save_docs/3 (src/cpse_util.erl, line 126)
in call from cpse_test_purge_seqs:cpse_increment_purge_seq_on_partial_purge/1 (src/cpse_test_purge_seqs.erl, line 103)
in call from eunit_test:run_testfun/1 (eunit_test.erl, line 83)
in call from eunit_proc:run_test/1 (eunit_proc.erl, line 554)
in call from eunit_proc:with_timeout/3 (eunit_proc.erl, line 379)
**throw:{invalid_json,{56,invalid_string}}
  output:<<"">>

big-r81 avatar Oct 01 '25 18:10 big-r81

Hey, did a test with QuickJS and I got 3 of the 4 errors too!

Failing Elixir tests:

UTF8Test [test/elixir/test/utf8_test.exs]
  * test UTF8 support (39.7ms) [L#12]

  1) test UTF8 support (UTF8Test)
     test/elixir/test/utf8_test.exs:12
     Assertion with in failed
     code:  assert status in [201, 202]
     left:  400
     right: [201, 202]
     stacktrace:
       (elixir 1.18.4) lib/enum.ex:987: Enum."-each/2-lists^foreach/1-0-"/2
       test/elixir/test/utf8_test.exs:25: (test)

Failing EUnit tests:

    cpse_test_purge_docs
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_simple)...[0.005 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_simple_info_check)...[0.005 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_empty_db)...[0.002 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_single_docid)...[0.005 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_multiple_docids)...[0.006 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_no_docids)...[0.002 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_rev_path)...[0.010 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_deep_revision_path)...[0.346 s] ok
      cpse_gather: -make_test_fun/3-fun-2- (cpse_purge_partial_revs)...*failed*
in function couch_util:json_decode/2 (src/couch_util.erl, line 486)
in call from cpse_util:'-save_docs/3-fun-0-'/1 (src/cpse_util.erl, line 128)
in call from lists:map/2 (lists.erl, line 2385)
in call from cpse_util:save_docs/3 (src/cpse_util.erl, line 126)
in call from cpse_test_purge_docs:cpse_purge_partial_revs/1 (src/cpse_test_purge_docs.erl, line 253)
in call from eunit_test:run_testfun/1 (eunit_test.erl, line 83)
in call from eunit_proc:run_test/1 (eunit_proc.erl, line 554)
in call from eunit_proc:with_timeout/3 (eunit_proc.erl, line 379)
**throw:{invalid_json,{55,invalid_string}}
  output:<<"">>
      cpse_gather: -make_test_fun/3-fun-2- (cpse_increment_purge_seq_on_partial_purge)...*failed*
in function couch_util:json_decode/2 (src/couch_util.erl, line 486)
in call from cpse_util:'-save_docs/3-fun-0-'/1 (src/cpse_util.erl, line 128)
in call from lists:map/2 (lists.erl, line 2385)
in call from cpse_util:save_docs/3 (src/cpse_util.erl, line 126)
in call from cpse_test_purge_seqs:cpse_increment_purge_seq_on_partial_purge/1 (src/cpse_test_purge_seqs.erl, line 103)
in call from eunit_test:run_testfun/1 (eunit_test.erl, line 83)
in call from eunit_proc:run_test/1 (eunit_proc.erl, line 554)
in call from eunit_proc:with_timeout/3 (eunit_proc.erl, line 379)
**throw:{invalid_json,{56,invalid_string}}
  output:<<"">>

This three failing tests have nothing to do with the SM140 it seems.

The test test runtime code evaluation can be prevented could be through the failing SM API, but I'm only guessing...

big-r81 avatar Oct 02 '25 07:10 big-r81