Commit Graph

19 Commits

Author SHA1 Message Date
Matthew Olsson
abb4b6d117 LibJSGCVerifier: Detect missing JS_CELL() calls 2024-04-09 09:13:06 +02:00
Matthew Olsson
312bc94ac9 LibJSGCVerifier: Detect missing JS_DECLARE_ALLOCATOR() calls
C++ classes that inherit from JS::Cell and are leaf classes should have
their own type-specific allocator. We also do this for non-leaf classes
that are constructable from JS.

To do this, JSON messages are passed to communicate information about
each class the Clang tool comes across. This is the only message we have
to worry about for now, but in the future if we want to transmit
different kinds of information, we can make this message format more
generic.
2024-04-09 09:13:06 +02:00
Matthew Olsson
dfce95ab0f LibJSGCVerifier: Support message passing between Clang processes
This allows each Clang process to send JSON messages to the
orchestrating Python process, which aggregates the message and can do
something with them all at the end. This is required because we run
Clang multithreaded to speed up the tool execution.

I did try to add a second frontend tool that accepts all the files at
once, but it was _extremely_ slow, so this is the next best thing.
2024-04-09 09:13:06 +02:00
Matthew Olsson
76fa127cbf LibJSGCVerifier: Detect stack-allocated ref captures in lambdas
For example, consider the following code snippet:

    Vector<Function<void()>> m_callbacks;
    void add_callback(Function<void()> callback)
    {
    	m_callbacks.append(move(callback));
    }

    // Somewhere else...
    void do_something()
    {
    	int a = 10;
    	add_callback([&a] {
            dbgln("a is {}", a);
    	});
    } // Oops, "a" is now destroyed, but the callback in m_callbacks
      // has a reference to it!

We now statically detect the capture of "a" in the lambda above and flag
it as incorrect. Note that capturing the value implicitly with a capture
list of `[&]` would also be detected.

Of course, many functions that accept Function<...> don't store them
anywhere, instead immediately invoking them inside of the function. To
avoid a warning in this case, the parameter can be annotated with
NOESCAPE to indicate that capturing stack variables is fine:

    void do_something_now(NOESCAPE Function<...> callback)
    {
    	callback(...)
    }

Lastly, there are situations where the callback does generally escape,
but where the caller knows that it won't escape long enough to cause any
issues. For example, consider this fake example from LibWeb:

    void do_something()
    {
    	bool is_done = false;
    	HTML::queue_global_task([&] {
            do_some_work();
            is_done = true;
        });
    	HTML::main_thread_event_loop().spin_until([&] {
            return is_done;
        });
    }

In this case, we know that the lambda passed to queue_global_task will
be executed before the function returns, and will not persist
afterwards. To avoid this warning, annotate the type of the capture
with IGNORE_USE_IN_ESCAPING_LAMBDA:

    void do_something()
    {
   	IGNORE_USE_IN_ESCAPING_LAMBDA bool is_done = false;
    	// ...
    }
2024-04-09 09:10:44 +02:00
Andreas Kling
e67f6343f7 LibJSGCVerifier: Warn on missing visit of JS::Value members
A JS::Value can refer to a GC-allocated object, so let's ensure they
are visited when necessary.
2024-04-07 18:01:50 +02:00
Matthew Olsson
f3096bd4a1 LibJSGCVerifier: Define the NULL constant
Not sure why this throws warnings, but its a simple fix
2024-04-07 07:03:13 +02:00
Idan Horowitz
9f31a83c2e LibJSGCVerifier: Assume MarkedVector wrapped members are valid
These are effectively heap roots, so they don't need to be visited.
2024-04-06 06:59:36 +02:00
Idan Horowitz
f921952cc3 LibJSGCVerifier: Warn about missing visit_edges impls with GC members
Previously we would only warn about missing calls to visit inside
visit_edges implementations, now we warn as well when there's no
visit_edges implementation at all.
2024-04-06 06:59:36 +02:00
Idan Horowitz
c84cd1d668 LibJSGCVerifier: Support marking GCPtr members as raw references
This lets us avoid false positives when a GCPtr-wrapped member is only
a weak reference which is automatically updated by the GC when the
member's gc state is updated.
2024-04-06 06:59:36 +02:00
Idan Horowitz
1fd6673f87 LibJSGCVerifier: Support building & running with the Lagom build 2024-04-05 21:49:13 +02:00
0x4261756D
f489c3d9c2 LibJSGCVerifier: Fix false positives in HeapFunction::visit_edges()
clang doesn't make all `Base::visit_edges()` calls CXXMemberCallExprs
This would lead to false positives like in HeapFunction,
where the matcher would fail to match and report a warning.
Also previously the matcher would succeed
if the visited class is missing the call to `Base::visit_edges()`
but an included class has a correct method.

The new matcher checks the current class for `visit_edges`-overrides
and matches all `visit_edges`-memberExprs inside,
checking those for starting with `Base::`.
This seems to get rid of the false positives
and should be more correct detecting missing calls.
2024-04-04 07:50:13 +02:00
0x4261756D
7743dcf4a9 LibJSGCVerifier: Fix dangling-reference errors
When building, clang would throw errors about dangling references.
Extracting `template_args` to a variable before the loop and
indexing into that seems to fix the errors.
2024-04-04 07:50:13 +02:00
Timothy Flynn
b54786ee95 LibJSGCVerifier: Use more general shebang line and clarify instructions
My system's python3 is not in /bin/.

The README did not indicate that a clang-toolchain build of Serenity is
required, so this patch adds that explicit instruction.
2023-11-30 08:49:15 +00:00
Aliaksandr Kalenik
da2c18d1f9 Meta: Update LibJSGCVerifier to build with llvm 16.0.6
Changes to fix LibJSGCVerifier build with llvm version used in
BuildClang.sh
2023-09-16 20:51:28 -06:00
Daniel Bertalan
e64a8751d1 LibJS: Do not use the $ special character in file names
The dollar sign is a special character in POSIX shells and in the Ninja
build file format. If the file name contains a `$`, something goes wrong
in the escaping/unescaping of this symbol, and CMake/GCC/Clang generate
invalid dependency files where not all instances of `$` are escaped
properly. Because of this, Ninja fails to rebuild `$262Object.cpp` if
the headers included by it have changed.

Stale `$262Object.cpp.o` files have been the cause of mysterious crashes
multiple times which only go away after doing a clean build. Let's
prevent these from happening again by removing the `$` from the
filename.
2023-07-15 11:09:22 -04:00
Matthew Olsson
48d92eecac Lagom: Enforce GC-allocated fields are visited in LibJSGCVerifier 2023-04-30 06:04:33 +02:00
Matthew Olsson
98ed74087f Lagom: Enforce uniform calls to Base::visit_edges in LibJSGCVerifier
This ensures that all visit_edges implementations include a call to
Base::visit_edges. In particular, this gives three nice benefits:

  - The call can't be forgotten (the main benefit, of course).
  - All of the calls look the same. In other words, always use "Base"
    instead of the actual concrete class.
  - Ensure the object has a call to JS_CELL or JS_OBJECT in the
    definition. Otherwise, Base will not be defined and the call will
    not compile.
2023-04-30 06:04:33 +02:00
Matthew Olsson
0c7eac8d9a Lagom: Remove debug line in LibJSGCVerifier 2023-03-15 08:48:49 +01:00
Matthew Olsson
b33b950e45 Lagom: Add a tool to verify correctness of the LibJS GC
This is implemented as a Clang frontend tool, and currently does two
things:
  - Ensure for all fields wrapped in {Nonnull,}GCPtr<T>, T inherits from
    JS::Cell
  - Ensure for all fields not wrapped in {Nonnull,}GCPtr, that the type
    does not inherit from JS::Cell (otherwise it should be wrapped in a
    Ptr class).

In the future, this tool could be extended further. For example, we may
consider validating all implementations of Cell::visit_impl.
2023-03-06 13:05:43 +00:00