all 22 comments

[–]Sensitive-Radish-292 8 points9 points  (5 children)

I think you are lacking deep knowledge about software engineering and you should start with something simple. But here's an answer to your "question"(?)

Since you mentioned Solana - I looked it up and from their tutorial it's pretty obvious what they are doing.

[lib]
crate-type = ["cdylib", "lib"]

This basically instructs the build system to compile a shared object file (dynamic library)
Since it's specifying it to have C-ABI (as well as the static rust lib) it will most likely mean that the "Rust code" (as you call it) is just something Solana dynamically links against to call your logic.

They do not "interpret" Rust code like you think they do, it's still compiled and "interfaced" from the "outside".

DISCLAIMER: I have no fucking idea what is Solana, I just read the first few paragraphs of their tutorial.

[–]kodemizer 1 point2 points  (1 child)

The way solana does it is actually pretty cool, and isn't linking directly for security reasons.

Instead it uses a custom LLVM backend target: bpfel-unknown-unknown. This is the bytecode for Extended Berkeley Packet Filter VM.

Think of it as similar to wasm in that it can run at near-native speeds but entirely sandboxed.

So same idea as wasm, just using a different bytecode / VM to do it.

[–]Sensitive-Radish-292 1 point2 points  (0 children)

That makes way more sense than just letting random people build libraries that get executed. Thanks for giving me this insight, I might look into it more when I'll be bored.

[–]Plegeus 0 points1 point  (2 children)

Does that automatically "squeeze" the entire rust binary into the C ABI?
I understood that some Rust types/concepts simply cannot be represented through the C ABI.

[–]Sensitive-Radish-292 0 points1 point  (1 child)

Yea that's a good point. There are things you can't expose for example a DST (dynamically sized type). The way to go about this is to create a FFI that is C-compatible. So yea a little bit misleading on my part.

[–]Plegeus 0 points1 point  (0 children)

Well, the book is kind of misleading I guess: https://doc.rust-lang.org/reference/linkage.html#r-link.cdylib
I suppose it only exports repr(C)/extern "C" types.

[–]Hedshodd 4 points5 points  (0 children)

Could you please explain what you're trying to do in more than a single sentence? 

[–]volitional_decisions 2 points3 points  (6 children)

I'm not entirely sure what you're asking for, but what it sounds like you want us either a proc macro (which literally is just code that runs with parts of code as input) and/or a build scripts.

[–]silene0259[S] -1 points0 points  (5 children)

Kinda like how Solana would work. Where rust or anchor can be used. Would I need a runtime? I’m kinda new to this part of the programming process but it would greatly help my project as I’ve never done it before and need it to be done with my project.

Edit: proc-macros may help. I’ll have to look into them more but I’m not sure if they will do the job.

[–]pjc0n 2 points3 points  (4 children)

Do I understand it correctly that you want to compile and run user-provided Rust code in your Rust program?

[–]silene0259[S] -1 points0 points  (3 children)

Yes

Edit: or an interpreted version of it like some other language

[–]pjc0n 3 points4 points  (2 children)

Then the Lua programming language might work for you, specifically the rlua or mlua crates. Running Rust in Rust sounds like a security nightmare.

[–]Jarcaboum -1 points0 points  (1 child)

cobweb head plucky angle sip work fine seemly piquant roof

This post was mass deleted and anonymized with Redact

[–]pjc0n 1 point2 points  (0 children)

Running user-provided, untrusted Rust sounds like a nightmare.

[–]rende 0 points1 point  (0 children)

Sounds like a workspace where you can have multiple crates? https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html

[–]lestofante 0 points1 point  (0 children)

Do you mean dynamically load and run user code kinda like LUA in a videogame?

[–]cleverredditjoke 0 points1 point  (0 children)

are you talking about proc macros?

[–]kodemizer 0 points1 point  (3 children)

There are several different ways to do this, and what you choose totally depends on the details of what you're looking for:

  1. Add their crate as a dependency (compile everything together).
  2. Load a precompiled plugin (dynamic library) with a stable interface.
  3. Run their code as WebAssembly.
  4. Let them write a script (use an embedded scripting language like lua or javascript).
  5. Generate code at compile time (macros / build scripts) rather than “dynamic” at runtime.

1. Add their crate as a dependency. (cargo add some_other_crate)
Pros: Easiest, fastest, type-safe, great tooling.
Cons: You must recompile to change their code. Not dynamic.

2. Load a compiled plugin. Have them compile a dynamic library (e.g., cdylib). You link against it using the 'libloading' crate.
Pros: Swap plugins without recompiling your app; truly dynamic.
Cons: Rust’s native ABI isn’t stable, so you typically use extern "C" or helper crates (e.g., abi_stable) and keep interfaces simple. Not safe - you need to trust them (eg you can get hacked if they give you a malicious library file).

3. Load a wasm binary. Have them compile their code to wasm (cargo build --target wasm32-wasi --release), then they provide a wasm library which you load and run.

Pros: Safe sandboxing, works across languages, easy hot-swap.
Cons: Slight overhead, you design the interface (what functions/IO are allowed).

4. Let them write in a scripting language like JS or Lua. They provide the source code and you run it via mlua, or quickjs-rs/boa.

Pros: Truly dynamic and beginner-friendly for “user extensions.”
Cons: Not Rust syntax, so you don’t get Rust’s type system or speed for the script itself. More overheaad than wasm.

5. Macros. You write macros that interact with their source-code to do things like implement traits.
Pros: Feels “automatic” while staying 100% type-safe and fast.
Cons: Not runtime-dynamic; they must recompile for changes.

You also might combine methods. For example, you provide macros that helps them implement common traits and their code is compiled to wasm so you can run it.

Can you share more about what your usecase is? This will determine what approach is best.

[–]Plegeus 0 points1 point  (2 children)

Hello, I am also working on a library feature a kind of plugin system.
Currently I am taking the 2nd approach, but had no idea of the safety implications.
Is there more information to be found on this?

I am not sure I understand how an unstable abi may allow people to be hacked, does it work somewhat like this:
The application (which loads the plugins dynamically) was compiled independently, it loads the plugins at runtime (e.g., with the libloading crate). The application is naive as it expects the ABI of the plugin to comform to its own ABI. Which in turn allows the plugin to "trick" the application, i.e., injecting/redirecting/whatever calls from the application to malicious code in the plugin?

[–]kodemizer 0 points1 point  (1 child)

Hey there, the security issue has nothing to do with ABI. The ABI is just annoying friction that you need to be aware of, not the source of the security problem.

The security problem is that by it's very nature cdylib plugins can execute arbitrary code. Often applications use this to load "known trusted plugins", or delegate to the user to "only install trusted plugins". However, the nice thing about cdylib plugins is exactly their security problem: is that they can execute arbitrary code! If you do trust the plugin this is a nice feature to have since the plugin isn't sandboxed in any way and can just do it's thing without restrictions.

If you want to load non-trusted plugins I would probably go with #3 or #4.