Skip to content

How should lint crates be loaded? #26

Open
@xFrednet

Description

@xFrednet

Hey 👋 I'm currently investigating ways, to load one or several lint crates from the lint driver. The current prototype loads lint crates as dynamic libraries and simply passes rust types to them. This is problematic, since Rust doesn't have a stable ABI. In fact, reading more about it, I'm surprised that it has worked flawlessly this far. I want to find a stable way to load them, as that might affect, how data is modeled and represented.

This also plays into this suggestion/discussion that lints should ideally be sandboxed.


This detailed blog about Plugins in Rust lists a few ways how this can be accomplished:

  1. Dynamic Libraries: The lint crates are compiled to dynamic libraries and then loaded. This requires a stable ABI for types and functions. This can be accomplished, but requires some extra work. This implementation is also fast, since the lint instructions are executed natively. But it doesn't allow for Sandboxing.
  2. WebAssembly (WASM): Lint crates would be compiled to WebAssembly, then loaded and run by a runtime. Every lint would be sandboxed by default. The main problem is, that the stable WASM interface only allows for the exchange of integers, floats, structs and enum. Pointers are not included, which makes sense, since the Sandbox is going to have its own memory addresses. This is problematic for an AST, which uses numerous references. Serializing them and then deserializing them would create a major overhead.
  3. Scripting Language: Implement lints in a scripting language like Lua, while possible, I would like to implement the linting logic in Rust and I guess most users would also prefer that.
  4. Compile the driver with lints: Another option would be to compile the driver on demand with the lint crates as dependencies. Lint crates would then be linked statically. This solution requires some code generation to bind the lint crates to the driver. All libraries required for the driver compilation (like nightly rustc) are required, and the additional compile time could also be noticed by the user.
  5. rlib files with Miri: Rusts static libraries can apparently be executed by Miri. Which would allow dynamic loading. However, miri is unstable and this is more a theory and nothing with a proof of concept.

Currently, there appears to be no ideal way to add plugin support to rust projects. Every solution I found can be derived from the first four listed ideas. I like the idea of using WASM and sandboxing everything by default, like dtolnay/watt does for proc macros. However, this collides with a tree representation with several references.

Dynamic libraries seam to be ideal, with the exception that they can't be sandboxed and restrict the implementation to a stable ABI (Meaning no dyn pointers)


cc: rust-marker/marker#8

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions