Plan 06: Runtime Engine Unification & Security Hardening
Goal: Unify standard library native dispatch between tree-walk and bytecode runtimes to eliminate behavioral divergence, and replace insecure shell string execution with argument vector process spawning. Inspiration: Go's single compiled runtime model and
os/exec.Command.
1. Problem Statement & Root Cause
Currently in Kyna:
- Behavioral Divergence between Tree-Walk and Bytecode:
sortin tree-walk is an $O(n^2)$ bubble sort (collections_library.cpp:L67-L114); in bytecode it isstd::stable_sort.- Higher-order methods (
filter,map,reduce) fail in bytecode mode (collections_invoke.cpp:L221-L226).
- Insecure Process Spawning (Shell Injection):
LocalProcess::runexecutesstd::system(command.c_str())with raw string concatenation (local_process.cpp:L12).project_dependencies.cppruns rawgit clonecommands usingstd::systemstring concatenation (project_dependencies.cpp:L103-L122).
- Test Fixtures in Production Code:
CurlNetwork::sendhardcodes a mock interceptor for"mock://kyna/users"(curl_network.cpp:L79-L83).
2. Target Architecture
2.1 Unified Native Binding Dispatcher
Instead of duplicating function bodies between library/core/src/catalog/*.cpp and library/core/src/bytecode/*_invoke.cpp, implement a shared C++ native registry:
namespace kyna::runtime {
using NativeFunction = std::function<Value(Span<Value> args, ExecutionContext& ctx)>;
class NativeRegistry {
public:
static NativeRegistry& instance();
void registerNative(std::string_view name, NativeFunction fn);
std::optional<Value> invoke(std::string_view name, Span<Value> args, ExecutionContext& ctx);
};
} // namespace kyna::runtimeBoth the bytecode VM and the tree-walk interpreter invoke natives through NativeRegistry.
2.2 Secure Process Spawning (ProcessPort)
namespace kyna::host {
struct ProcessConfig {
std::string program;
std::vector<std::string> args;
std::filesystem::path workingDir;
std::unordered_map<std::string, std::string> env;
};
struct ProcessResult {
int exitCode;
std::string stdoutText;
std::string stderrText;
};
class ProcessPort {
public:
virtual ~ProcessPort() = default;
virtual ProcessResult spawn(const ProcessConfig& config) = 0;
};
} // namespace kyna::hostImplemented via posix_spawn / execv on POSIX and CreateProcessW on Windows — zero shell interpolation.
3. Implementation Steps
- Step 1: Create Shared
NativeRegistry- Implement under
runtime/kyna_vm/src/execution/native_registry.cpp.
- Implement under
- Step 2: Migrate Core Standard Library Builtins
- Move implementations of
print,len,push,pop,sortinto the unified registry.
- Move implementations of
- Step 3: Remove Mock Interceptor from
CurlNetwork- Delete mock URL check from
curl_network.cpp. Use mock network port in tests.
- Delete mock URL check from
- Step 4: Refactor
LocalProcessto Use Vector Spawning- Replace
std::systemwith safe argument vector execution.
- Replace
- Step 5: Refactor CLI Dependency Manager
- Update
project_dependencies.cppto callProcessPort::spawnwith{"git", "clone", ...}.
- Update
4. Verification Plan
- Test Native Parity:
- Run identical scripts through both
--tree-walkand--bytecodeand verify identical outputs.
- Run identical scripts through both
- Security & Process Tests:
- Test passing arguments containing spaces, quotes, and shell metacharacters (
;&|) without shell injection.
- Test passing arguments containing spaces, quotes, and shell metacharacters (
Source captured: 2026-10-11