Add API version checking for modules.

Checking now actively implemented for dynamic modules
in a fully backwards compatible way.
This commit is contained in:
Calvin Rose 2019-05-29 21:57:03 -04:00
parent c8c6419013
commit bcbe42ab23
5 changed files with 66 additions and 25 deletions

View File

@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.
## Unreleased
- Add API compatibility checking for modules. This will let native modules not load
when the host program is not of a compatible version or configuration.
## 0.6.0 - 2019-05-29
- `file/close` returns exit code when closing file opened with `file/popen`.
- Add `os/rename`

View File

@ -26,14 +26,15 @@
#include "fiber.h"
#endif
static JanetBuildConfig *api_build_config = &(JanetBuildConfig) {
.api_version = JANET_API_VERSION,
.single_threaded = JANET_SINGLE_THREADED_BIT,
.nanbox = JANET_NANBOX_BIT
static const JanetBuildConfig api_build_config = (JanetBuildConfig) {
JANET_VERSION_MAJOR,
JANET_VERSION_MINOR,
JANET_VERSION_PATCH,
JANET_CURRENT_CONFIG_BITS
};
const JanetBuildConfig *janet_build_config() {
return api_build_config;
const JanetBuildConfig *janet_config_host(void) {
return &api_build_config;
}
void janet_panicv(Janet message) {

View File

@ -63,7 +63,30 @@ JanetModule janet_native(const char *name, const uint8_t **error) {
}
init = (JanetModule) symbol_clib(lib, "_janet_init");
if (!init) {
*error = janet_cstring("could not find _janet_init symbol");
*error = janet_cstring("could not find the _janet_init symbol");
return NULL;
}
JanetBuildConfig(*modconf_getter)(void) = symbol_clib(lib, "_janet_mod_config");
if (!modconf_getter) {
*error = janet_cstring("could not find the _janet_mod_config symbol");
return NULL;
}
JanetBuildConfig modconf = modconf_getter();
JanetBuildConfig host = janet_config_current();
if (host.major != modconf.major ||
host.minor < modconf.minor ||
host.bits != modconf.bits) {
char errbuf[128];
sprintf(errbuf, "config mismatch - host %d.%.d.%d(%.4x) vs. module %d.%d.%d(%.4x)",
host.major,
host.minor,
host.patch,
host.bits,
modconf.major,
modconf.minor,
modconf.patch,
modconf.bits);
*error = janet_cstring(errbuf);
return NULL;
}
return init;
@ -830,6 +853,9 @@ JanetTable *janet_core_env(JanetTable *replacements) {
JDOC("The version number of the running janet program."));
janet_def(env, "janet/build", janet_cstringv(JANET_BUILD),
JDOC("The build identifier of the running janet program."));
janet_def(env, "janet/config-bits", janet_wrap_integer(JANET_CURRENT_CONFIG_BITS),
JDOC("The flag set of config options from janetconf.h which is used to check "
"if native modules are compatible with the host program."));
/* Allow references to the environment */
janet_def(env, "_env", janet_wrap_table(env), JDOC("The environment table for the current scope."));

View File

@ -31,8 +31,6 @@ extern "C" {
#include "janetconf.h"
#define JANET_API_VERSION 1
#ifndef JANET_VERSION
#define JANET_VERSION "latest"
#endif
@ -186,26 +184,38 @@ extern "C" {
#endif
#endif
/* Runtime config constants */
#ifdef JANET_NO_NANBOX
#define JANET_NANBOX_BIT 0
#else
#define JANET_NANBOX_BIT 1
#define JANET_NANBOX_BIT 0x1
#endif
#ifdef JANET_SINGLE_THREADED
#define JANET_SINGLE_THREADED_BIT 1
#define JANET_SINGLE_THREADED_BIT 0x2
#else
#define JANET_SINGLE_THREADED_BIT 0
#endif
#define JANET_CURRENT_CONFIG_BITS \
(JANET_SINGLE_THREADED_BIT | \
JANET_NANBOX_BIT)
/* Represents the settings used to compile Janet, as well as the version */
typedef struct {
int api_version;
int single_threaded : 1;
int nanbox : 1;
unsigned major;
unsigned minor;
unsigned patch;
unsigned bits;
} JanetBuildConfig;
/* Get config of current compilation unit. */
#define janet_config_current() ((JanetBuildConfig){ \
JANET_VERSION_MAJOR, \
JANET_VERSION_MINOR, \
JANET_VERSION_PATCH, \
JANET_CURRENT_CONFIG_BITS })
/***** END SECTION CONFIG *****/
/***** START SECTION TYPES *****/
@ -1276,15 +1286,11 @@ JANET_API void janet_register(const char *name, JanetCFunction cfun);
/* New C API */
#define JANET_MODULE_ENTRY JANET_API void _janet_init
JANET_API int janet_api_version();
JANET_API const JanetBuildConfig *janet_build_config();
#define janet_api_compatible() \
((janet_api_build_config()->api_version == JANET_API_VERSION) \
&& (janet_api_build_config()->nanbox == JANET_NANBOX_BIT) \
&& (janet_api_build_config()->single_threaded == JANET_SINGLE_THREADED_BIT))
#define JANET_MODULE_ENTRY \
JANET_API JanetBuildConfig _janet_mod_config(void) { \
return janet_config_current(); \
} \
JANET_API void _janet_init
JANET_API void janet_panicv(Janet message);
JANET_API void janet_panic(const char *message);

View File

@ -25,7 +25,11 @@
#ifndef JANETCONF_H
#define JANETCONF_H
#define JANET_VERSION "0.6.0"
#define JANET_VERSION_MAJOR 0
#define JANET_VERSION_MINOR 6
#define JANET_VERSION_PATCH 0
#define JANET_VERSION_EXTRA "-dev"
#define JANET_VERSION "0.6.0-dev"
/* #define JANET_BUILD "local" */