{"id":15144636,"url":"https://github.com/lemonrock/predicator","last_synced_at":"2025-10-23T22:30:56.685Z","repository":{"id":62442872,"uuid":"93750808","full_name":"lemonrock/predicator","owner":"lemonrock","description":"Predicator, a Rust crate for generating and running dynamic code","archived":false,"fork":false,"pushed_at":"2018-09-25T10:40:13.000Z","size":192,"stargazers_count":16,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-19T13:23:25.982Z","etag":null,"topics":["libc","llvm-ir","llvm-jit-plugins","plugin","plugin-manager","rust","rust-crate"],"latest_commit_sha":null,"homepage":"https://github.com/lemonrock/predicator","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lemonrock.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-08T13:11:20.000Z","updated_at":"2024-09-06T13:22:08.000Z","dependencies_parsed_at":"2022-11-01T22:16:37.991Z","dependency_job_id":null,"html_url":"https://github.com/lemonrock/predicator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lemonrock/predicator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonrock%2Fpredicator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonrock%2Fpredicator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonrock%2Fpredicator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonrock%2Fpredicator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lemonrock","download_url":"https://codeload.github.com/lemonrock/predicator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lemonrock%2Fpredicator/sbom","scorecard":{"id":584063,"data":{"date":"2025-08-11","repo":{"name":"github.com/lemonrock/predicator","commit":"37407fb035a43e91779492fa08245eb0a690a2a1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-20T19:57:19.881Z","repository_id":62442872,"created_at":"2025-08-20T19:57:19.881Z","updated_at":"2025-08-20T19:57:19.881Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280706308,"owners_count":26376965,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-23T02:00:06.710Z","response_time":142,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["libc","llvm-ir","llvm-jit-plugins","plugin","plugin-manager","rust","rust-crate"],"created_at":"2024-09-26T11:00:16.898Z","updated_at":"2025-10-23T22:30:56.357Z","avatar_url":"https://github.com/lemonrock.png","language":"Rust","readme":"# predicator\n\n[predicator] is a rust crate that lets you write plug ins that are can be loaded and unloaded and optimized at runtime, in Rust and any other language that LLVM JIT supports. It's ideal for filters, security checks and short-lived snippets of code that live for 10s to 100s of seconds in long-lived processes.\n\nIt is thread safe, but plugins are limited to `#[no_std]` crates at this time. A longer term plan is to add support for hosting cargo, and experimenting with symbol resolvers.\n\nStatically-linked programs will work, but if they use a third-party library (even the libc), then they'll need to be specially compiled to pull in those definitions.\n\n\n## Impatient to get getting?\n\nLook at `src/main.rs`. This is all you need to create and load a plug in. Creation can be in a separate process, or even on a separate machine.\n\nDemonstrate it works on your machine with `cargo run`. You'll need Rust nightly. Tested on Mac OS X as of 9th June 2017.\n\n\n## Writing a Plug In\n\n\n### Setting up `Cargo.toml`\n\nThe values in `Cargo.toml` need to be carefully set in order to generate a suitable plug-in.\n\n\n#### Firstly, make sure the `[profile]` section contains these two entries exactly:-\n\n```toml\n[profile.dev]\nopt-level = 3\ndebug = true\nrpath = false\nlto = true\ndebug-assertions = true\ncodegen-units = 1\npanic = 'abort'\n\n[profile.release]\nopt-level = 3\ndebug = false\nrpath = false\nlto = true\ndebug-assertions = false\ncodegen-units = 1\npanic = 'abort'\n```\n\nThe settings of `lto = true` is particularly important. The setting of `panic = abort` isn't strictly necessary, but, as there is no way to pass panics in a LLVM JIT plugin back to Rust, makes development a little easier, as panics will die safely during development and debug testing.\n\n\n#### Secondly, add or replace the `[lib]` section so it matches this exactly:-\n\n```toml\ncrate-type = [\"bin\"]\n```\n\n\n### Writing the code for a LLVM JIT plugin\n\nA LLVM JIT plugin needs some boiler plate code in order to work. Put this code at the *top* of your `lib.rs`:-\n\n```rust\n#![no_std]\n#![feature(lang_items)]\n#![feature(libc)]\n#![no_main]\n\n\nextern crate libc;\n\n\n#[lang = \"panic_fmt\"]\nfn panic_fmt() -\u003e !\n{\n    loop\n\t{\n\t}\n}\n\n#[lang = \"eh_personality\"]\nextern fn eh_personality()\n{\n}\n\n#[allow(unused_variables)]\n#[cfg(not(debug_assertions))]\n#[no_mangle]\npub extern fn main(argc: isize, argv: *const *const u8) -\u003e isize\n{\n    0\n}\n\n#[cfg(debug_assertions)]\n#[no_mangle]\npub extern fn main(argc: isize, argv: *const *const u8) -\u003e isize\n{\n    test(argc, argv)\n}\n\n/// Change this code to run unit tests when compiled in `debug` mode\n/// Return a non-zero value to mark a test failure\nfn test(argc: isize, argv: *const *const u8) -\u003e isize\n{\n\t0\n}\n```\n\nThis code does the following:-\n\n* Tells the Rust compiler to use just the `core` crate (also known as `libcore`)\n\t* This means anything requiring (heap) memory allocation isn't available\n\t\t* No collections (eg `Vec`, `HashSet`, etc)\n\t\t* No `Box`, `Rc` or `Arc`\n\t\t* No strings (`String`, `str`, `CString`, `CStr`, `OsString` and `OsStr`)\n\t\t* No paths (`Path`, `PathBuf`)\n\t\t* And other similar restrictions\n\t* Also, that code that panics is not particularly useful\n* Tells the Rust compiler that we will supply language item functions missing from `core`\n* Tells the Rust compiler that we will use its toolchain's version of the `libc` crate (not strictly necessary in advanced scenarios)\n* Tells the Rust compiler not to generate the usual logic to support Rust's `main()` function, as we don't need them for a plugin\n* Uses the `libc` crate; without it, the plugin won't compile as it relies on the libc start files like `crt1.o`\n* Adds a definition of `panic_fmt()` which endlessly loops; this isn't ideal (a better solution is probablty to write to stderr or syslog)\n* Adds a piece of code to support exeption handling which does nothing\n* Defines a `main()` method suitable for calling from libc, which does nothing when used in release mode. This is to make it possible to compile the code.\n* Defines a `main()` method that handles bridging to C and then forwards to a `test()` method\n* Defines a stub `test()` function, which you can replace with logic to test your code\n\nNow you're reading to go. Just write normal functions and code. To make a function usable, it will need to be `pub` and `#[no_mangle]`.\n\nFor example, a really simple function might be:-\n\n```rust\n#[no_mangle]\npub fn simple_plugin()\n{\n}\n```\n\nThis could then be used as a LLVM JIT plugin by looking up the function `simple_plugin` as:-\n\n```rust\nextern crate predicator;\n\n\nuse ::predicator::llvm::*;\n\n\nfn main()\n{\n\t// Create a super context\n\tlet super_context = SuperContext::threadLocal();\n\t\n\t// There needs to be at least one context per thread\n\tlet jit_context = super_context.newJitContext(NaiveSymbolResolver(0)).expect(\"Could not create a new JIT context\");\n\t\n\t// Can also be created from a slice, and from intermediate representation (.ll files)\n\tlet plugins = jit_context.loadPlugins(ModuleSourceCodeType::BitCode, \u0026MemoryBufferCreator::File(\"/path/to/bitcode/file.bc\")).expect(\"Could not parse bit code into module\");\n\t\n\t// Note that there is no way to know the correct arity or arguments for the function pointer\n\tlet simple_plugin_function_pointer = plugins.nullaryFunctionPointer::\u003c()\u003e(\"simple_plugin\").expect(\"Missing function for simple_plugin\");\n\t\n\t// Execute the function\n\tunsafe { simple_plugin_function_pointer() };\n\t\n\t// Note that once `plugins` is dropped the function pointer is no longer valid\n}\n```\n\nFunctions can also make use of anything defined in the `core` crate. Be wary of using anything in the `libc` crate, as LLVM JIT plugins can be used with statically-linked code and so libc functions and global statics may not have been linked in to the program using your plugin. This caveat does not apply when running the plug in directly to test it.\n\nFunction can take arguments and return results, eg this plugin:-\n\n```rust\npub fn binary_plugin(size: usize, some_array: [u8; 2]) -\u003e u32\n{\n\t17\n}\n```\n\nCan then be used like this:-\n\n```rust\n\tlet binary_plugin_function_pointer = orcJitStack.binaryFunctionPointer::\u003cu32, usize, [u8; 64]\u003e(\"binary_plugin\").expect(\"Missing function for binary_plugin\");\n\t\n\t// Execute the function\n\tlet size = 20;\n\tlet some_array = [3, 9];\n\tlet result = unsafe { binary_plugin_function_pointer(size, some_array) };\n\tassert!(result == 17, \"result wasn't 17\");\n```\n\nBe aware that you are crossing the equivalent of a 'C' boundary. The predicator framework can not prevent you from not catching panic!, passing `Box` values, mismatching types, etc. It is recommended that you stick to very simple structures and primitives. More complexity will work, but it is extremely hard to debug when something breaks. There is nothing to stop you using types from other `no_std` crates, but you should avoid importing global (or thread local) statics from them. Defining global statics and thread local statics in the plugin code should be fine, however.\n\n\n### Building\n\nTo build the LLVM JIT plugin, use:-\n\n```bash\ncargo rustc --release --target x86_64-unknown-linux-musl -- --emit=llvm-bc\n```\n\n_NOTE: We need to check if `-C relocation-model=static` is needed_\n\n_NOTE: The switch `-C lto` should not actually be needed if your `Cargo.toml` is correctly set up._\n\nYou can find the output inside wherever `cargo` has defined the target folder. If you've forked this crate, you'll find it at `.cargo/target/x86_64-unknown-linux-musl/release/deps/NAME_OF_CRATE-HEX_RANDOM_VALUE.bc` where `NAME_OF_CRATE` is the name of your crate and `RANDOM_VALUE` is the value of `-C metadata=RANDOM_VALUE -C extra-filename=-RANDOM_VALUE cargo passes as part of the build. An example path might be `.cargo/target/x86_64-unknown-linux-musl/release/deps/experiment_with_ffi-805d16cbb3e10aad.bc`. When cargo builds it produces build output that contains a hint to this path:-\n\n```bash\n   Compiling experiment-with-ffi v0.0.0 (file:///Volumes/Source/GitHub/lemonrock/experiment-with-ffi)\n     Running `rustc --crate-name experiment_with_ffi src/lib.rs --crate-type bin --emit=dep-info,link -C opt-level=3 -C panic=abort -C lto --emit=llvm-bc -C metadata=24221fe0742db2e8 -C extra-filename=-24221fe0742db2e8 --out-dir /Volumes/Source/GitHub/lemonrock/experiment-with-ffi/.cargo/target/x86_64-unknown-linux-musl/release/deps --target x86_64-unknown-linux-musl -C ar=x86_64-linux-musl-ar -C linker=x86_64-linux-musl-cc -L dependency=/Volumes/Source/GitHub/lemonrock/experiment-with-ffi/.cargo/target/x86_64-unknown-linux-musl/release/deps -L dependency=/Volumes/Source/GitHub/lemonrock/experiment-with-ffi/.cargo/target/release/deps`\n    Finished release [optimized] target(s) in 0.25 secs\n```\n\nIn this scenario, `NAME_OF_CRATE` is `experiment-with-ffi` and `RANDOM_VALUE` is `24221fe0742db2e8`, seen above as `-C metadata=24221fe0742db2e8 -C extra-filename=-24221fe0742db2e8`\n\n#### Alternative build approaches\n\n\n##### Debug mode\n\nTo build in debug mode use:-\n\n```bash\ncargo rustc --target x86_64-unknown-linux-musl -- --emit=llvm-bc\n```\n\n\n##### To check the LLVM IR code the plugin is created from\n\nTo check the generated LLVM IR, use:-\n\n```bash\ncargo rustc --release --target x86_64-unknown-linux-musl -- --emit=llvm-ir\n```\n\nThis code is *not* built in debug mode, as it becomes very difficult to read. If you want to build it in debug mode, omit the `--release` switch above.\n\n\n##### Stripping Release Mode Code\n\nBy default, the LLVM IR and bit code generated by Rust's compiler contains some additional debug information even when generated with `--release`. This can be removed using the `opt` program.\n\nTo removeit from IR code (`.ll` files), do the following:-\n\n```bash\nopt -strip-debug -S -o .cargo/target/x86_64-unknown-linux-musl/release/deps/NAME_OF_CRATE-RANDOM_VALUE.stripped.ll .cargo/target/x86_64-unknown-linux-musl/release/deps/NAME_OF_CRATE-RANDOM_VALUE.ll\n```\n\nand from bit code (`.bc` files):-\n\n```bash\nopt -strip-debug -o .cargo/target/x86_64-unknown-linux-musl/release/deps/NAME_OF_CRATE-RANDOM_VALUE.stripped.bc .cargo/target/x86_64-unknown-linux-musl/release/deps/NAME_OF_CRATE-RANDOM_VALUE.bc\n```\n\nNote the absence of the `-S` switch.\n\n*Interestingly, the generated `.ll` code can sometimes be smaller than the `.bc` code.* I've observed as much as 24%.\n\n\n## Thanks\n\nWith thanks to the tutorial at \u003chttps://github.com/jauhien/iron-kaleidoscope#chapter-3-optimizer-and-jit-support\u003e\n\n\n## Licensing\n\nThe license for this project is AFGPL-3.0.\n\n[predicator]: https://github.com/lemonrock/predicator \"predicator GitHub page\"\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonrock%2Fpredicator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flemonrock%2Fpredicator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flemonrock%2Fpredicator/lists"}