February 2021
Mo Tu We Th Fr Sa Su
<< >>


Neko Modules Loader

Posted on Jul 10 2005

I'm done with implementing Modules Loader in NekoVM. The idea is to be able to dynamically load a module and filter/secure the access it makes to other modules or C primitives. A module loader then have two functions (in pseudo-typing) :

  function loadmodule( modname : String, loader : Loader ) : Module
  function loadprim( primname : String, primargs : int ) : Function

The loadmodule method is called when the loaded module request the access to another module. In the default loader this function will load the module, initialize it, and returns its export table, which is an object whose fields have been set using : $exports.myvar = 1234 for example. Since the export table is an object, the user can write his own loadmodule function that will allow only some modules to be loaded (raising an expection or returning null either) or that can modify or wrap the export table in order to secure, add traces, filter, .... the module accesses. This is very powerful feature that opens a lot of different usages.

The loadprim method resolve and load a C primitive using its name and number of arguments as parameters, and returns a function. The default loader split the name of the primitive in two : std_fileopen with 3 args will load the DLL std and get the std_fileopen__3 C function, then call it in order to retrieve the pointer to the real C functions (all theses registrations are done with some Neko C API Macros). Again, the user can define his own loader using another behavior for loadprim : he can filter the C primitives that are accessible, or return a wrapper function that does additional checks (for example in our fileopen sample, the user can ensure that the module will not try to access files outside a given directory).

This loading process is very useful for both debugging and security. It also adds dynamic loading of modules which is a nice feature. The default loader currently cache the modules after they're loaded, so modules cannot be unloaded right now, but that might be a possibility later, since all module functions are keeping a reference to the module, we can be sure that as long as we keep an accessible function, the module will not be garbage-collected.

Also, there is no check for recursive modules loading. If a module A loads B which in turn loads A, then the A export table returned to B will be filled only with values that have been set at the time A loaded B. Since we return a copy of the export table (because we don't want it to be modified by another module), at the end of both A and B initialization, B might have a broken A table. This is not a very predictable behavior, but if the user know what he's doing with recursive modules, it should be ok. One workaround is to set an "api" object field in the export table and then fill this object, so mutations done in A will occur also in B (export tables are not copied recursively).

A module loader example :

    var myloader = $new(null);
    myloader.loadmodule = function(mname,curloader) {
        $print("loading module ",mname);
        if( mname == "system" ) $throw("Cannot access system");
        return $loader.loadmodule(mname,curloader);
    myloader.loadprim = function(pname,pargs)  {
        $print("loading primitive "+pname+" with "+pargs+" arguments");
        if( $ssub(pname,0,7) == "system_" )
            $throw("Cannot access system");
        return $loader.loadprim(pname,pargs);

Please note that since we're passing recursively myloader to loadmodule second parameter, the module secure.n as well as all modules it's loading will use our custom loader.

0 comment
Name : Email : Website : Message :