#ifndef CCDJIT_PUBLIC_H #define CCDJIT_PUBLIC_H /* * CCDJIT public embedding API * * This header is the stable boundary for hosts that want to compile and run C * code at runtime. The implementation lives in ccdjit.c, but the intended use * should be clear from this file alone. * * Basic use: * * ccdjit_context *ctx = ccdjit_context_new(NULL); * ccdjit_module *module = NULL; * * if (ccdjit_compile_string(ctx, source, "plugin.c", &module) == 0) { * int result = 0; * ccdjit_module_call_main(module, 0, NULL, &result); * ccdjit_module_free(module); * } * ccdjit_context_free(ctx); * * Return convention: * Functions returning int use 0 for success and -1 for failure unless * documented otherwise. On failure, call ccdjit_context_last_error(). * * Lifetime: * A context owns options, include paths, registered symbols, and the last * diagnostic. A module owns generated code or a loaded CCDJIT binary. * Modules keep their context state alive, so ccdjit_context_free() may be * called before ccdjit_module_free(); the context is released when the * last module using it is freed. * Function pointers returned by ccdjit_module_symbol() are invalid after * ccdjit_module_free(). * * Threads: * Independent contexts may compile and run from different threads. Do * not mutate or use the same context or module concurrently from multiple * threads unless the host provides its own synchronization. * * Safety: * Normal calls run in the host process. Set sandbox_execution to * CCDJIT_SANDBOX_PROCESS to run ccdjit_module_call_main() in a child * process with optional resource, syscall, and filesystem limits. */ #include #include #ifdef __cplusplus extern "C" { #endif typedef struct ccdjit_context ccdjit_context; typedef struct ccdjit_module ccdjit_module; typedef struct { /* Host compiler or linker driver. NULL uses $CC, then cc. */ const char *driver; /* Extra linker arguments such as -L, -l, or -Wl options. */ const char *const *link_args; size_t link_arg_count; /* Print the host linker command to stderr when nonzero. */ int verbose; } ccdjit_link_options; /* * Host symbol callback. Return NULL when the name is unknown. * * The returned pointer is used as an external function or object address by * generated code. Keep any pointed-to object alive while modules using it may * run. */ typedef void *(*ccdjit_symbol_resolver)(const char *name, void *userdata); typedef enum { /* Run generated code directly in the host process. */ CCDJIT_SANDBOX_OFF = 0, /* Run ccdjit_module_call_main() in a forked child process. */ CCDJIT_SANDBOX_PROCESS = 1, } ccdjit_sandbox_mode; typedef enum { /* * Minimal child profile: enough to write the result pipe, write * captured output, and exit. Unexpected syscalls are trapped. */ CCDJIT_SANDBOX_SYSCALL_STRICT = 0, /* STRICT plus read/close for simple stdio-style code. */ CCDJIT_SANDBOX_SYSCALL_STDIO = 1, /* STDIO plus mmap/munmap/mprotect/brk/clock_gettime. */ CCDJIT_SANDBOX_SYSCALL_RUNTIME = 2, /* Disable the seccomp filter. Resource limits still apply. */ CCDJIT_SANDBOX_SYSCALL_PERMISSIVE = 3, } ccdjit_sandbox_syscall_policy; typedef enum { /* Runtime file syscalls are denied by the syscall policy. */ CCDJIT_SANDBOX_FS_NONE = 0, /* Permit read-only access under explicitly added roots. */ CCDJIT_SANDBOX_FS_READ_ONLY_ROOTS = 1, /* Permit writes only for roots added with writable != 0. */ CCDJIT_SANDBOX_FS_WRITABLE_ROOTS = 2, } ccdjit_sandbox_filesystem_policy; typedef struct { /* Allow #include to read files from include paths. */ int allow_filesystem_includes; /* Allow the preprocessor to discover and read host system includes. */ int allow_system_includes; /* Allow executable mappings for JIT code and loaded CCDJIT binaries. */ int allow_executable_memory; /* ccdjit_sandbox_mode. Default is CCDJIT_SANDBOX_OFF. */ int sandbox_execution; /* ccdjit_sandbox_syscall_policy. Default is STRICT. */ int sandbox_syscalls; /* ccdjit_sandbox_filesystem_policy. Default is FS_NONE. */ int sandbox_filesystem; /* * In sandbox mode, default dlsym lookup is disabled unless this is set. * Prefer explicit ccdjit_context_register_symbol() capabilities. */ int sandbox_allow_implicit_symbols; /* Wall-clock timeout for one sandboxed main call. Zero means no limit. */ unsigned int sandbox_timeout_ms; /* RLIMIT_CPU for sandboxed calls, rounded up to seconds by the OS. */ unsigned int sandbox_cpu_time_ms; /* RLIMIT_AS for sandboxed calls. Zero means keep the host default. */ size_t sandbox_address_space_bytes; /* RLIMIT_STACK for sandboxed calls. Zero means keep the host default. */ size_t sandbox_stack_bytes; /* RLIMIT_FSIZE for sandboxed calls. Zero means keep the host default. */ size_t sandbox_file_size_bytes; /* Captured stdout/stderr cap for sandboxed calls. Zero means 64 KiB. */ size_t sandbox_output_limit_bytes; /* * Preprocessor output byte cap. Zero uses the default currently 128 * MiB. */ size_t preprocessor_output_limit_bytes; /* Macro expansion recursion cap. Zero uses the default. */ unsigned int preprocessor_macro_depth_limit; /* Nested include cap. Zero uses the default. */ unsigned int preprocessor_include_depth_limit; } ccdjit_options; typedef struct { /* Compiler phase such as LEXER, PARSER, JIT, API, or SANDBOX. */ const char *phase; /* Source file, binary path, symbol name, or "". */ const char *filename; /* Human-readable error text owned by the context. */ const char *message; /* Optional source excerpt for lexer/parser/type diagnostics. */ const char *source_line; const char *caret_line; /* One-based line and column when available, otherwise zero. */ int line; int column; /* Raw child wait status or errno-style value for sandbox/API failures. */ int status; /* Signal that terminated the sandbox child, or zero. */ int signal_number; } ccdjit_diagnostic; /* Create a compiler context. Passing NULL uses permissive CLI-like defaults. */ ccdjit_context *ccdjit_context_new(const ccdjit_options *options); /* Free the context and all context-owned diagnostics/options/lists. */ void ccdjit_context_free(ccdjit_context *ctx); /* Add a preprocessor include search path, like -I. */ int ccdjit_context_add_include_path(ccdjit_context *ctx, const char *path); /* Restrict filesystem includes to this root when include roots are used. */ int ccdjit_context_add_include_root(ccdjit_context *ctx, const char *path); /* Add a preprocessor definition, like -DNAME or -DNAME=value. */ int ccdjit_context_add_define(ccdjit_context *ctx, const char *define); /* Grant generated code an explicit external symbol capability. */ int ccdjit_context_register_symbol(ccdjit_context *ctx, const char *name, void *addr); /* Add an explicit shared library path for external symbol lookup. */ int ccdjit_context_add_library(ccdjit_context *ctx, const char *path); /* Install a fallback external symbol resolver. */ void ccdjit_context_set_symbol_resolver(ccdjit_context *ctx, ccdjit_symbol_resolver resolver, void *userdata); /* Update sandbox mode, syscall policy, filesystem policy, and symbol policy. */ int ccdjit_context_set_sandbox_options(ccdjit_context *ctx, int mode, int syscall_policy, int filesystem_policy, int allow_implicit_symbols); /* Update all sandbox resource limits in one call. */ int ccdjit_context_set_sandbox_limits(ccdjit_context *ctx, unsigned int timeout_ms, unsigned int cpu_time_ms, size_t address_space_bytes, size_t stack_bytes, size_t file_size_bytes, size_t output_limit_bytes); /* Update preprocessor resource limits. Passing zero keeps the default. */ int ccdjit_context_set_preprocessor_limits(ccdjit_context *ctx, size_t output_limit_bytes, unsigned int macro_depth, unsigned int include_depth); /* * Add a Landlock filesystem root for sandboxed execution. * * writable is only honored when sandbox_filesystem is * CCDJIT_SANDBOX_FS_WRITABLE_ROOTS. On systems without Landlock, requesting a * root-based filesystem policy fails while entering the sandbox. */ int ccdjit_context_add_sandbox_filesystem_root(ccdjit_context *ctx, const char *path, int writable); /* Return the last error for this context. The pointer is context-owned. */ const ccdjit_diagnostic *ccdjit_context_last_error(ccdjit_context *ctx); /* Return captured sandbox stdout/stderr from the last sandboxed main call. */ const char *ccdjit_context_last_stdout(ccdjit_context *ctx); const char *ccdjit_context_last_stderr(ccdjit_context *ctx); /* Compile a source file into a live JIT module. */ int ccdjit_compile_file(ccdjit_context *ctx, const char *path, ccdjit_module **out); /* Compile a source string into a live JIT module. */ int ccdjit_compile_string(ccdjit_context *ctx, const char *source, const char *filename, ccdjit_module **out); /* * Compile a source file into a live JIT module without requiring main(). * Use ccdjit_module_symbol() to find and call exported config/plugin symbols. */ int ccdjit_compile_file_module(ccdjit_context *ctx, const char *path, ccdjit_module **out); /* * Compile a source string into a live JIT module without requiring main(). * Use ccdjit_module_symbol() to find and call exported config/plugin symbols. */ int ccdjit_compile_string_module(ccdjit_context *ctx, const char *source, const char *filename, ccdjit_module **out); /* Convenience wrapper: compile a source string, call main, free the module. */ int ccdjit_eval_string(ccdjit_context *ctx, const char *source, const char *filename, int argc, char **argv, int *result_out); /* * Find a function or object symbol in a module. * * Calling the returned function pointer runs in the host process even when the * context has sandbox_execution enabled. Use ccdjit_module_call_main() for * sandboxed execution. */ void *ccdjit_module_symbol(ccdjit_module *module, const char *name); /* Call module main(argc, argv). Honors CCDJIT_SANDBOX_PROCESS. */ int ccdjit_module_call_main(ccdjit_module *module, int argc, char **argv, int *result_out); /* Emit textual assembly-like bytes for inspection. */ int ccdjit_module_emit_assembly(ccdjit_module *module, FILE *out); /* Emit a CCDJITB2 binary image. */ int ccdjit_module_emit_binary(ccdjit_module *module, FILE *out); /* Emit an ELF64 relocatable object. */ int ccdjit_module_emit_object(ccdjit_module *module, FILE *out); /* * Emit a linked host executable. * * This depends on the host compiler driver. It is intended for trusted build * paths, not sandboxed execution. */ int ccdjit_module_emit_executable_file(ccdjit_module *module, const char *path, const ccdjit_link_options *options); /* Emit a CCDJITB2 binary image directly to a path. */ int ccdjit_module_emit_binary_file(ccdjit_module *module, const char *path); /* Load a CCDJITB2 binary image into executable memory. */ int ccdjit_module_load_binary(ccdjit_context *ctx, const char *path, ccdjit_module **out); /* Free generated code, loaded binary storage, AST, and module-owned source. */ void ccdjit_module_free(ccdjit_module *module); #ifdef __cplusplus } #endif #endif