#include "cvm_core.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
# include <windows.h>
#else
# include <dlfcn.h>
#endif
int ffi_load(Runtime *rt, const char *path) {
if (rt->ffi_count >= 16) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "FFI: 已加载库数量达到上限");
rt->has_error = 1;
return -1;
}
void *lib = NULL;
#ifdef _WIN32
lib = (void *)LoadLibraryA(path);
if (!lib) {
char tmp[300];
snprintf(tmp, sizeof(tmp), "%s.dll", path);
lib = (void *)LoadLibraryA(tmp);
}
#else
const char *real_path = path;
if (strcmp(path, "msvcrt") == 0) real_path = "libc.so.6";
lib = dlopen(real_path, RTLD_LAZY);
if (!lib) {
char tmp[300];
snprintf(tmp, sizeof(tmp), "%s.so", real_path);
lib = dlopen(tmp, RTLD_LAZY);
}
#endif
if (!lib) {
snprintf(rt->errbuf, sizeof(rt->errbuf), "FFI: 无法加载动态库 '%s'", path);
rt->has_error = 1;
return -1;
}
rt->ffi_libs[rt->ffi_count].lib = lib;
snprintf(rt->ffi_libs[rt->ffi_count].path, sizeof(rt->ffi_libs[0].path), "%s", path);
rt->ffi_count++;
return 0;
}
void *ffi_resolve(Runtime *rt, const char *name) {
void *cached = map_get(&rt->ffi_syms, name);
if (cached) return cached;
#ifndef _WIN32
const char *real_name = name;
if (strcmp(name, "_atoi64") == 0) real_name = "atoll";
#else
const char *real_name = name;
#endif
for (int i = 0; i < rt->ffi_count; ++i) {
#ifdef _WIN32
void *p = (void *)GetProcAddress((HMODULE)rt->ffi_libs[i].lib, name);
#else
void *p = dlsym(rt->ffi_libs[i].lib, real_name);
#endif
if (p) {
map_set(&rt->ffi_syms, name, p);
return p;
}
}
return NULL;
}
void *ffi_resolve_allowed(Runtime *rt, const char *name) {
if (rt->ffi_allow_sym.count == 0 || !map_get(&rt->ffi_allow_sym, name)) {
if (rt->ffi_allow_sym.count == 0) {
snprintf(rt->errbuf, sizeof(rt->errbuf),
"FFI 未启用 (运维未配置 cvmruntime.ffi)");
} else {
snprintf(rt->errbuf, sizeof(rt->errbuf),
"FFI 符号未授权 (不在 cvmruntime.ffi 白名单): %s", name);
}
rt->has_error = 1;
return NULL;
}
return ffi_resolve(rt, name);
}
int rt_load_ffi_allowfile(Runtime *rt, const char *filename) {
FILE *fp = fopen(filename, "r");
if (!fp) return -1;
char line[512];
while (fgets(line, sizeof(line), fp)) {
size_t len = strlen(line);
while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r')) line[--len] = '\0';
char *s = line;
while (*s == ' ' || *s == '\t') s++;
if (s[0] == '\0' || s[0] == '#') continue;
char *colon = strchr(s, ':');
if (!colon) {
snprintf(rt->errbuf, sizeof(rt->errbuf),
"cvmruntime.ffi 格式错误 (缺 ':' 分隔): %s", s);
rt->has_error = 1; fclose(fp); return -1;
}
char *lib = s;
while (lib < colon && (*lib == ' ' || *lib == '\t')) lib++;
char *lib_end = colon;
while (lib_end > lib && (lib_end[-1] == ' ' || lib_end[-1] == '\t')) lib_end--;
*lib_end = '\0';
if (lib_end == lib) {
snprintf(rt->errbuf, sizeof(rt->errbuf),
"cvmruntime.ffi 库路径为空");
rt->has_error = 1; fclose(fp); return -1;
}
char *symlist = colon + 1;
Map *sub = (Map *)calloc(1, sizeof(Map));
if (!sub) { fclose(fp); return -1; }
map_init(sub);
char *tok = strtok(symlist, ",");
while (tok) {
while (*tok == ' ' || *tok == '\t') tok++;
char *end = tok + strlen(tok);
while (end > tok && (end[-1] == ' ' || end[-1] == '\t')) end--;
*end = '\0';
if (tok[0] != '\0') {
map_set(sub, tok, (void *)1);
map_set(&rt->ffi_allow_sym, tok, (void *)1);
}
tok = strtok(NULL, ",");
}
map_set(&rt->ffi_allow, lib, (void *)sub);
}
fclose(fp);
rt->ffi_enabled = 1;
return 0;
}
void ffi_close(void *lib) {
if (!lib) return;
#ifdef _WIN32
FreeLibrary((HMODULE)lib);
#else
dlclose(lib);
#endif
}