Skip to content

Updated Sylvan to version 1.9.1#1882

Merged
mlaveaux merged 18 commits intomCRL2org:masterfrom
mlaveaux:feature/sylvan-1.9.1
Mar 20, 2026
Merged

Updated Sylvan to version 1.9.1#1882
mlaveaux merged 18 commits intomCRL2org:masterfrom
mlaveaux:feature/sylvan-1.9.1

Conversation

@mlaveaux
Copy link
Copy Markdown
Member

@mlaveaux mlaveaux commented Nov 7, 2025

Updated Sylvan to the latest version, this pull request is simply to run the CI. This should resolve thread safety issues for ARM processors.

@mlaveaux mlaveaux self-assigned this Nov 7, 2025
@mlaveaux mlaveaux added the enhancement Something can be improved label Nov 8, 2025
@mlaveaux
Copy link
Copy Markdown
Member Author

In Sylvan 1.9.1. the LACE_ME macro was removed, that we are using in several places. Instead, it is now necessary to define lace tasks explicitly to use the RUN macro for all of them. This includes various functions that we were already using and things that were explicit C functions but that should be executed from within a lace thread. Furthermore, it seems that protection should also be performed within the LACE thread, so we need various wrappers to apply the protection before returning to the main thread.

@trolando
Copy link
Copy Markdown

Ideally you should not need to make any changes to Sylvan/Lace so that future upgrades are seamless.

  set(LACE_ENABLE_PIC ON CACHE BOOL "" FORCE)
  add_subdirectory(3rd-party/lace/)
  set(SYLVAN_ENABLE_PIC ON CACHE BOOL "" FORCE)
  add_subdirectory(3rd-party/sylvan/)

Comment thread tools/release/lpsreach/lpsreach.cpp Outdated
Comment thread tools/release/pbessolvesymbolic/pbessolvesymbolic.cpp Outdated
Comment thread tools/developer/ltsconvertsymbolic/ltsconvertsymbolic.cpp
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably cleaner to do this in CMakeLists.txt of mCRL2.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already include this in the v2.x.x branch of Lace, I can backport the -fPIC stuff to the lace-1 branch if that makes this cleaner.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember why -fPIC was required, but this would probably be helpful indeed. The set(LACE_ENABLE_PIC ON CACHE BOOL "" FORCE) trick does not seem to be sufficient to resolve the linking errors:

: && /home/mlaveaux/.cargo/bin/sccache  clang++ -fPIC -O2 -g -DNDEBUG   -shared -Wl,-soname,libmcrl2_symbolic.so -o stage/lib/libmcrl2_symbolic.so libraries/symbolic/CMakeFiles/mcrl2_symbolic.dir/source/ldd_stream.cpp.o  -Wl,-rpath,/home/mlaveaux/mCRL2/build/stage/lib:  stage/lib/libmcrl2_data.so  3rd-party/sylvan/src/lib/libsylvan.a  stage/lib/libmcrl2_core.so  stage/lib/libmcrl2_atermpp.so  stage/lib/libdparser.so  stage/lib/libmcrl2_utilities.so  -ldl  3rd-party/lace/lib/liblace.a  -lpthread  -lm && :
/usr/bin/ld: 3rd-party/lace/lib/liblace.a(lace.c.o): relocation R_X86_64_TPOFF32 against `current_worker' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: failed to set dynamic section sizes: bad value
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's because Lace doesn't have it yet, it's part of the changes in Lace v2. I can backport it to Lace v1.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah my bad, I misunderstood. It seems that we can work around it from the mCRL2 side with these two lines, so perhaps backporting is not necessary:

set_target_properties(sylvan PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
set_target_properties(lace PROPERTIES POSITION_INDEPENDENT_CODE TRUE)

@trolando
Copy link
Copy Markdown

Is the current design intended to use the C++ wrappers from different threads, or are ltsreach and pbessolvesymbolic by themselves single-threaded?

If every call is from the same thread, then this is fine. Otherwise, some work needs to be done to ensure that garbage collection doesn't erase BDDs that are only referenced by a result that is currently only stored as a return value from an external task. For example by wrapping each (!) call in something like this:

VOID_TASK_3(bdd_and_wrapped, mtbdd*, result, mtbdd, lhs, mtbdd, rhs)
void bdd_and_wrapped(mtbdd* result, mtbdd lhs, mtbdd rhs) {
    *result = CALL(bdd_and, lhs, rhs);
}

@mlaveaux
Copy link
Copy Markdown
Member Author

@trolando. These tools are all single threaded and only call Sylvan operations from the main thread. However, from what I remember we call some functions that are not guarded by the RUN macro. I suppose the easiest solution would be to wrap the whole tool implementation inside a lace task.

@trolando
Copy link
Copy Markdown

Yes, that would work. Wrap the whole program in a Lace task if this doesn't cause issues with thread-specific variables you are using and things like that. It will always be an improvement if you can wrap a single-threaded program into a Lace task because then there's less overhead from the context switches.

In Sylvan 2.0 I am very likely going to make some changes here though. One of the goals is easier support for Java, Python bridges etc. Most likely all methods will move to the "bdd_op(result_ptr, param1, param2, ...)" format for any operation which computes a BDD. I also intend to change it so if there is an out of memory, it sets the result to a magic value SYLVAN_OUTOFMEM or something like that, instead of crashing out. This also enables a potential future option to use the return value for something else.

@trolando
Copy link
Copy Markdown

Let me know if there's anything I should do on the Sylvan/Lace side.

The current roadmap is that I'm adding "proper" Windows (MSVC) support to Lace and Sylvan. I have completed this for Lace 2.0 and am working on the Sylvan version. How much urgency is there for supporting Windows natively? I could try to backport these changes to the Lace 1.x branch and the Sylvan 1.x (master) branch, which would then allow mCRL2 to use Sylvan in Windows (MSVC). Currently Windows is supported via MSYS2 (POSIX).

@mlaveaux
Copy link
Copy Markdown
Member Author

@trolando I think most of our users know how to use WSL by now since also our compiling rewriter also does not work on Windows/MSVC. So I think backporting might not be that urgent, but having MSVC supports would be nice.

The lace macros contain code that is not valid in C++ code:

compound literals are a C99-specific feature [-Wc99-extensions]
   51 | TASK_DECL_1(bool, pbessolvesymbolic_task, arguments*);

Before this was not so much of an issue since it was all in Sylvan itself. We can probably ignore this for the time being, but I think given the fact that it is somewhat necessary to use the lace tasks in the C++ side as well it would be nice if the macros only produced compliant C++ code.

Copilot AI review requested due to automatic review settings February 26, 2026 19:08
@mlaveaux mlaveaux force-pushed the feature/sylvan-1.9.1 branch from 1aa9f4e to feaadc7 Compare February 26, 2026 19:08

This comment was marked as off-topic.

@trolando
Copy link
Copy Markdown

Well, that's a pretty silly review, considering that the availability of Lace ensures that the FetchContent bit is never active.

I'm fairly sure the compound literals warning comes from something like this:

        ts = (TailSplitNA){{head,head+1}};

which could probably be replaced by

        ts.ts.head  = head;                                                          
        ts.ts.split = head + 1;                                                      

I just don't know if the generated assembly will be different.

@trolando
Copy link
Copy Markdown

By the way you can if you want do a git rebase -i on these commits to get rid of the reverts and clean it up, it's picked up by the pull request logic on Github.

@trolando
Copy link
Copy Markdown

By the way which compiler gave the error compound literals are a C99-specific feature [-Wc99-extensions]? MSVC?

@mlaveaux
Copy link
Copy Markdown
Member Author

I get these warnings on clang version 18.1.3 @trolando, possibly related to the pedantic flag.

@mlaveaux
Copy link
Copy Markdown
Member Author

It seems that thread sanitizer reports some data race, although it could be a false positive I thought it would at least be good to check with @trolando. There are also some reports of lace_start leaking a thread even though I do use lace_stop. If you think it's fine I will add a suppression file, not all fences/constructs are supported by the thread sanitizer:

WARNING: ThreadSanitizer: data race (pid=630120)
  Write of size 1 at 0x7fffe3f91040 by thread T5:
    #0 lace_steal /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.h:599:31 (libmcrl2_symbolic.so+0x41d2e) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #1 lace_steal_random_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:636:23 (libmcrl2_symbolic.so+0x3f804) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #2 lace_steal_random_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:626:1 (libmcrl2_symbolic.so+0x3f804)
    #3 lace_together_root_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1228:28 (libmcrl2_symbolic.so+0x40f5a) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #4 lace_together_root_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1219:1 (libmcrl2_symbolic.so+0x40f5a)
    #5 lace_together_root_WRAP /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1219:1 (libmcrl2_symbolic.so+0x40e20) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #6 lace_exec_in_new_frame /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1183:5 (libmcrl2_symbolic.so+0x40c3e) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #7 lace_yield /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1212:5 (libmcrl2_symbolic.so+0x40d7b) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #8 lace_steal_loop_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:689:9 (libmcrl2_symbolic.so+0x3fbb6) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #9 lace_steal_loop_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:649:1 (libmcrl2_symbolic.so+0x3fbb6)
    #10 lace_steal_loop_WRAP /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:649:1 (libmcrl2_symbolic.so+0x3f8bb) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #11 lace_exec_in_new_frame /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1183:5 (libmcrl2_symbolic.so+0x40c3e) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #12 lace_yield /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1212:5 (libmcrl2_symbolic.so+0x40d7b) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #13 lace_steal_loop_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:689:9 (libmcrl2_symbolic.so+0x40668) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #14 lace_worker_thread /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:728:5 (libmcrl2_symbolic.so+0x40668)
  Previous read of size 1 at 0x7fffe3f91040 by thread T11:
    #0 lddmc_refs_mark_r_par_SPAWN /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:157:1 (libmcrl2_symbolic.so+0x1868b) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #1 lddmc_refs_mark_task_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:195:5 (libmcrl2_symbolic.so+0x1868b)
    #2 lddmc_refs_mark_task_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:191:1 (libmcrl2_symbolic.so+0x1868b)
    #3 lddmc_refs_mark_task_WRAP /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:191:1 (libmcrl2_symbolic.so+0x1849f) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #4 lace_together_root_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1222:5 (libmcrl2_symbolic.so+0x40eb5) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #5 lace_together_root_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1219:1 (libmcrl2_symbolic.so+0x40eb5)
    #6 lace_together_root_WRAP /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1219:1 (libmcrl2_symbolic.so+0x40e20) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #7 lace_exec_in_new_frame /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1183:5 (libmcrl2_symbolic.so+0x40c3e) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #8 lace_yield /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1212:5 (libmcrl2_symbolic.so+0x40d7b) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #9 lace_steal_loop_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:689:9 (libmcrl2_symbolic.so+0x3fbb6) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #10 lace_steal_loop_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:649:1 (libmcrl2_symbolic.so+0x3fbb6)
    #11 lace_steal_loop_WRAP /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:649:1 (libmcrl2_symbolic.so+0x3f8bb) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #12 lace_exec_in_new_frame /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1183:5 (libmcrl2_symbolic.so+0x40c3e) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #13 lace_yield /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:1212:5 (libmcrl2_symbolic.so+0x40d7b) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #14 lace_steal_loop_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:689:9 (libmcrl2_symbolic.so+0x40668) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #15 lace_worker_thread /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:728:5 (libmcrl2_symbolic.so+0x40668)
  Thread T5 (tid=630126, running) created by main thread at:
    #0 pthread_create <null> (librarytest_mcrl2_symbolic_ldd_stream_test+0x6f16f) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #1 lace_start /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:944:9 (libmcrl2_symbolic.so+0x402c7) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #2 mcrl2::symbolic::initialise_sylvan() /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/libraries/symbolic/include/mcrl2/symbolic/test_utility.h:125:3 (librarytest_mcrl2_symbolic_ldd_stream_test+0x130e12) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #3 random_test_ldd_stream::test_method() /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/libraries/symbolic/test/ldd_stream_test.cpp:62:3 (librarytest_mcrl2_symbolic_ldd_stream_test+0x130e12)
    #4 random_test_ldd_stream_invoker() /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/libraries/symbolic/test/ldd_stream_test.cpp:60:1 (librarytest_mcrl2_symbolic_ldd_stream_test+0x130e12)
    #5 boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) /usr/include/boost/function/function_template.hpp:117:11 (librarytest_mcrl2_symbolic_ldd_stream_test+0x18c47b) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #6 boost::function0<void>::operator()() const /usr/include/boost/function/function_template.hpp:771:14 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1887f9) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #7 boost::detail::forward::operator()() /usr/include/boost/test/impl/execution_monitor.ipp:1395:32 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1887f9)
    #8 boost::detail::function::function_obj_invoker0<boost::detail::forward, int>::invoke(boost::detail::function::function_buffer&) /usr/include/boost/function/function_template.hpp:137:18 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1887f9)
    #9 boost::function0<int>::operator()() const /usr/include/boost/function/function_template.hpp:771:14 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109025) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #10 int boost::detail::do_invoke<boost::shared_ptr<boost::detail::translator_holder_base>, boost::function<int ()>>(boost::shared_ptr<boost::detail::translator_holder_base> const&, boost::function<int ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:308:30 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109025)
    #11 boost::execution_monitor::catch_signals(boost::function<int ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:910:16 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109025)
    #12 boost::execution_monitor::execute(boost::function<int ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:1308:16 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109339) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #13 boost::execution_monitor::vexecute(boost::function<void ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:1404:5 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1052c5) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #14 boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function<void ()> const&, unsigned long) /usr/include/boost/test/impl/unit_test_monitor.ipp:49:9 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1052c5)
    #15 boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned long, boost::unit_test::framework::state::random_generator_helper const*) /usr/include/boost/test/impl/framework.ipp:815:44 (librarytest_mcrl2_symbolic_ldd_stream_test+0x141ef6) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #16 boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned long, boost::unit_test::framework::state::random_generator_helper const*) /usr/include/boost/test/impl/framework.ipp:740:54 (librarytest_mcrl2_symbolic_ldd_stream_test+0x142046) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #17 boost::unit_test::framework::run(unsigned long, bool) /usr/include/boost/test/impl/framework.ipp:1722:29 (librarytest_mcrl2_symbolic_ldd_stream_test+0x103fb0) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #18 boost::unit_test::unit_test_main(boost::unit_test::test_suite* (*)(int, char**), int, char**) /usr/include/boost/test/impl/unit_test_main.ipp:250:9 (librarytest_mcrl2_symbolic_ldd_stream_test+0x120d69) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #19 main /usr/include/boost/test/impl/unit_test_main.ipp:306:12 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1215c7) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
  Thread T11 (tid=630132, running) created by main thread at:
    #0 pthread_create <null> (librarytest_mcrl2_symbolic_ldd_stream_test+0x6f16f) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #1 lace_start /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.c:944:9 (libmcrl2_symbolic.so+0x402c7) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #2 mcrl2::symbolic::initialise_sylvan() /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/libraries/symbolic/include/mcrl2/symbolic/test_utility.h:125:3 (librarytest_mcrl2_symbolic_ldd_stream_test+0x130e12) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #3 random_test_ldd_stream::test_method() /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/libraries/symbolic/test/ldd_stream_test.cpp:62:3 (librarytest_mcrl2_symbolic_ldd_stream_test+0x130e12)
    #4 random_test_ldd_stream_invoker() /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/libraries/symbolic/test/ldd_stream_test.cpp:60:1 (librarytest_mcrl2_symbolic_ldd_stream_test+0x130e12)
    #5 boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) /usr/include/boost/function/function_template.hpp:117:11 (librarytest_mcrl2_symbolic_ldd_stream_test+0x18c47b) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #6 boost::function0<void>::operator()() const /usr/include/boost/function/function_template.hpp:771:14 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1887f9) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #7 boost::detail::forward::operator()() /usr/include/boost/test/impl/execution_monitor.ipp:1395:32 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1887f9)
    #8 boost::detail::function::function_obj_invoker0<boost::detail::forward, int>::invoke(boost::detail::function::function_buffer&) /usr/include/boost/function/function_template.hpp:137:18 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1887f9)
    #9 boost::function0<int>::operator()() const /usr/include/boost/function/function_template.hpp:771:14 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109025) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #10 int boost::detail::do_invoke<boost::shared_ptr<boost::detail::translator_holder_base>, boost::function<int ()>>(boost::shared_ptr<boost::detail::translator_holder_base> const&, boost::function<int ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:308:30 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109025)
    #11 boost::execution_monitor::catch_signals(boost::function<int ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:910:16 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109025)
    #12 boost::execution_monitor::execute(boost::function<int ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:1308:16 (librarytest_mcrl2_symbolic_ldd_stream_test+0x109339) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #13 boost::execution_monitor::vexecute(boost::function<void ()> const&) /usr/include/boost/test/impl/execution_monitor.ipp:1404:5 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1052c5) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #14 boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function<void ()> const&, unsigned long) /usr/include/boost/test/impl/unit_test_monitor.ipp:49:9 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1052c5)
    #15 boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned long, boost::unit_test::framework::state::random_generator_helper const*) /usr/include/boost/test/impl/framework.ipp:815:44 (librarytest_mcrl2_symbolic_ldd_stream_test+0x141ef6) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #16 boost::unit_test::framework::state::execute_test_tree(unsigned long, unsigned long, boost::unit_test::framework::state::random_generator_helper const*) /usr/include/boost/test/impl/framework.ipp:740:54 (librarytest_mcrl2_symbolic_ldd_stream_test+0x142046) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #17 boost::unit_test::framework::run(unsigned long, bool) /usr/include/boost/test/impl/framework.ipp:1722:29 (librarytest_mcrl2_symbolic_ldd_stream_test+0x103fb0) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #18 boost::unit_test::unit_test_main(boost::unit_test::test_suite* (*)(int, char**), int, char**) /usr/include/boost/test/impl/unit_test_main.ipp:250:9 (librarytest_mcrl2_symbolic_ldd_stream_test+0x120d69) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
    #19 main /usr/include/boost/test/impl/unit_test_main.ipp:306:12 (librarytest_mcrl2_symbolic_ldd_stream_test+0x1215c7) (BuildId: 275dd266b6042c85b7a30fc2821f4748d9d79409)
SUMMARY: ThreadSanitizer: data race /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/lace/src/lace.h:599:31 in lace_steal
==================
==================
WARNING: ThreadSanitizer: data race (pid=630120)
  Write of size 1 at 0x7fffd31fd040 by thread T23:
    #0 lddmc_gc_mark_rec_SPAWN /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.h:96:1 (libmcrl2_symbolic.so+0x1704e) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)
    #1 lddmc_gc_mark_rec_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:39:9 (libmcrl2_symbolic.so+0x1704e)
    #2 lddmc_gc_mark_rec_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:33:1 (libmcrl2_symbolic.so+0x1704e)
    #3 lddmc_refs_mark_r_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:161:13 (libmcrl2_symbolic.so+0x17d87) (BuildId: 2459ec81088d1badf0c32cbad6d8d7d42473aea0)

@trolando
Copy link
Copy Markdown

trolando commented Feb 27, 2026

Yes, there are quite a few intentional data races in Lace.

The one reported here is on the movesplit variable. It is regularly read by the owner and set by thieves if there is more work but it's not in the shared portion of the deque. It is intentionally not protected by a mutex, as the data race is harmless. Maybe it should be a C11 atomic variable with all access explicitly memory_order_relaxed to officially prevent undefined behavior.

There are more such data races, e.g., allstolen works along the same lines, and a more tricky one is on the tailsplit union and its components tail and split which is actually an interesting case for program verification.

Regarding the leaking thread: if you inspect lace_stop, it waits until the workers_running variable is set to 0. This is the last thing a Lace worker does (decrease workers_running) so in theory it may be possible that when lace_stop returns, a thread is still running but about to terminate. I could actually fix that by storing the handles and explicitly joining with the threads, so I'll add that to the list, but it is just a minor issue.

@mlaveaux
Copy link
Copy Markdown
Member Author

I think it should indeed be a relaxed atomic since data races are instantly undefined behaviour in C++. The relaxed atomics should be free on x86_64, but I don't know about ARM processors. The other issue is probably indeed not joining the thread, although I don't know what this would matter in C++.

@trolando
Copy link
Copy Markdown

trolando commented Mar 1, 2026

Is dealing with these data races and the threading stuff a show stopped? I can fix lace_stop and that should probably work, but I don't know how much I need to do to ensure that the rest of Lace passes the AddressSanitizer checks. I can make some changes and pray that it suffices.... or figure out how to run those tests in the Lace build maybe...

@mlaveaux
Copy link
Copy Markdown
Member Author

mlaveaux commented Mar 2, 2026

I think we can technically work around it for the time being by maintaining a suppression file for the thread sanitizer warnings.

@trolando
Copy link
Copy Markdown

trolando commented Mar 2, 2026

Okay, this was a fair bit of work. I think I managed to address the problem for now. Lace v1.5.2 should not trigger the sanitizer anymore. Not sure about Sylvan, though.

Some of these are fairly annoying to deal with. For example, after allocating memory with mmap, other threads writing to that memory are flagged as data races even though there should not be an interleaving where the mmap is not finished by the time other threads touch that memory.

@mlaveaux
Copy link
Copy Markdown
Member Author

mlaveaux commented Mar 4, 2026

Most of the data races seem to be resolved @trolando, there is still one being reported within Sylvan itself:

EDIT: I forgot to mention, but this is with the latest version of Sylvan and lace 1.5.2.

WARNING: ThreadSanitizer: data race (pid=701204)
  Write of size 8 at 0x7fffe196ea80 by thread T39:
    #0 llmsset_lookup2 /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c (libmcrl2_symbolic.so+0x32b7e) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #1 llmsset_lookup /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:198:12 (libmcrl2_symbolic.so+0x32b08) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #2 lddmc_makenode /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:365:22 (libmcrl2_symbolic.so+0x1976e) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #3 lddmc_cube /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:1878:12 (libmcrl2_symbolic.so+0x219cb) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #4 lddmc_cube /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:1878:36 (libmcrl2_symbolic.so+0x219bc) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #5 lddmc_cube /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:1878:36 (libmcrl2_symbolic.so+0x219bc) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #6 lddmc_cube /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:1878:36 (libmcrl2_symbolic.so+0x219bc) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)

WARNING: ThreadSanitizer: data race (pid=701204)
  Read of size 8 at 0x7ffff7597038 by thread T46:
    #0 llmsset_rehash_bucket /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:224:37 (libmcrl2_symbolic.so+0x3348b) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #1 llmsset_rehash_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:402:21 (libmcrl2_symbolic.so+0x349a1) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #2 llmsset_rehash_par_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:390:1 (libmcrl2_symbolic.so+0x349a1)
    #3 llmsset_rehash_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:394:19 (libmcrl2_symbolic.so+0x348b9) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #4 llmsset_rehash_par_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:390:1 (libmcrl2_symbolic.so+0x348b9)
    #5 llmsset_rehash_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:394:19 (libmcrl2_symbolic.so+0x348b9) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #6 llmsset_rehash_par_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:390:1 (libmcrl2_symbolic.so+0x348b9)
    #7 llmsset_rehash_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:394:19 (libmcrl2_symbolic.so+0x348b9) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #8 llmsset_rehash_par_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:390:1 (libmcrl2_symbolic.so+0x348b9)
    #9 llmsset_rehash_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:394:19 (libmcrl2_symbolic.so+0x348b9) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)
    #10 llmsset_rehash_par_CALL /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:390:1 (libmcrl2_symbolic.so+0x348b9)
    #11 llmsset_rehash_par_WORK /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_table.c:394:19 (libmcrl2_symbolic.so+0x348b9) (BuildId: 44321c911ab5ff98a689919e65675eb5c6a7789c)

Furthermore, it seems that the undefined behaviour sanitizer reports on some misaligned read. I don't know if this is something you intend to resolve, but I figured I would mention it any way.

/scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd_int.h:102:5: runtime error: store to misaligned address 0x72315707a726 for type 'uint32_t' (aka 'unsigned int'), which requires 4 byte alignment
0x72315707a726: note: pointer points here
 00 00 00 00 00 00  00 00 02 00 00 00 00 00  01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00
             ^
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd_int.h:102:5
/scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd_int.h:46:12: runtime error: load of misaligned address 0x723158200066 for type 'uint32_t' (aka 'unsigned int'), which requires 4 byte alignment
0x723158200066: note: pointer points here
 00 00 00 00 01 00  00 00 0a 00 00 00 00 00  00 00 00 00 00 00 03 00  00 00 04 00 00 00 00 00  00 00
             ^
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd_int.h:46:12
/scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_common.c:405:9: runtime error: call to function lddmc_quit through pointer to incorrect function type 'void (*)(void)'
/scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_ldd.c:327: note: lddmc_quit defined here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /scratch/teamcity/BuildAgent/work/c1149d302b50fc7c/src/3rd-party/sylvan/src/sylvan_common.c:405:9

@trolando
Copy link
Copy Markdown

The misaligned read is something that's been there for as long as LDD has been in the package.

mddnode_getvalue(mddnode_t n)
{
    return *(uint32_t*)((uint8_t*)n+6);
}

In Sylvan 2.0 this node structure will change so the misaligned read might also go away then. I could backport this change already to the 1.9.x versions however it also changes the binary file format so I'd rather wait until Sylvan 2.0 with that change.

The error regarding lddmc_quit() can probably be fixed by making that lddmc_quit(void).

The data race: one thread is doing a pretty standard table lookup, the other one is in the middle of garbage collection. That would be an error. Are you sure you are not calling lddmc_cube directly from an external thread?

@trolando
Copy link
Copy Markdown

You could update to Sylvan v1.9.4 and Lace v1.5.3 which should resolve some issues.

@mlaveaux mlaveaux merged commit b08e2ac into mCRL2org:master Mar 20, 2026
5 of 9 checks passed
@mlaveaux mlaveaux deleted the feature/sylvan-1.9.1 branch March 20, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Something can be improved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants