Permalink
Browse files

Made the modules lib no longer depend on the filelib, and made the cr…

…oc interpreter work properly when running files in safe mode. These two changes make it possible to run files safely and allow them to import files.
  • Loading branch information...
JarrettBillingsley committed Nov 22, 2015
1 parent a89bec8 commit c71276fa3159c434ef310f723ee25f7550dbf2cc
Showing with 105 additions and 28 deletions.
  1. +37 −23 croc.cpp
  2. +62 −0 src/croc/stdlib/modules.cpp
  3. +6 −5 src/croc/stdlib/modules.croc
View
@@ -15,6 +15,7 @@ local _loadLibs = _croctmp._loadLibs
local _setInterruptibleThread = _croctmp._setInterruptibleThread
local _haltWasTriggered = _croctmp._haltWasTriggered
local _resetInterrupt = _croctmp._resetInterrupt
local _loadFileLib = _croctmp._loadFileLib
local Version = "Croc alpha"
@@ -30,7 +31,8 @@ local namespace ExitCode
local ShortUsage = [=[
Usage:
croc [options] [filename [args]] run file with args, or enter REPL
croc [options] enter REPL
croc [options] filename [args] run <filename> with args
croc [options] -e "string" run "string"
croc --compile outpath filename compile module to bytecode
croc --doctable outname filename extract doctable as JSON
@@ -244,13 +246,11 @@ local function parseArguments(args: array)
default:
if(args[i].startsWith("--docs"))
{
local pos = args[i].find('=')
local _, eq, mode = args[i].partition('=')
if(pos == #args[i])
if(eq is '' or mode is '')
return argError(ret, "Malfomed flag: '{}'", args[i]);
local mode = args[i][pos + 1 ..]
switch(mode)
{
case "on", "off", "default":
@@ -265,10 +265,12 @@ local function parseArguments(args: array)
}
else if(args[i].startsWith("-"))
return argError(ret, "Unknown flag '{}'", args[i])
ret.inputFile = args[i]
ret.args = args[i + 1 ..]
break
else
{
ret.inputFile = args[i]
ret.args = args[i + 1 ..]
break
}
}
break
@@ -377,7 +379,15 @@ local function doCompile(inputFile: string, outputFile: string)
return ExitCode.OK
}
local function doFile(inputFile: string, docsEnabled: string, args: array)
local function unloadFileLib()
{
hash.remove(modules.loaded, 'file')
hash.remove(modules.customLoaders, 'file')
hash.remove(_G, 'file')
gc.collect()
}
local function doFile(isSafe: bool, inputFile: string, docsEnabled: string, args: array)
{
if(docsEnabled is "on")
compiler.setFlags("alldocs")
@@ -390,11 +400,17 @@ local function doFile(inputFile: string, docsEnabled: string, args: array)
{
local fd, modName
if(isSafe)
_loadFileLib();
if(inputFile[-1] is 'o')
fd, modName = serialization.deserializeModule(stream.MemblockStream(file.readMemblock(inputFile)))
else
fd, modName = compiler.compileModule(file.readTextFile(inputFile), inputFile)
if(isSafe)
unloadFileLib();
modules.customLoaders[modName] = fd
modToRun = modName
}
@@ -451,18 +467,8 @@ local class ReplInout : repl.ConsoleInout
rets.set((:_thread)())
catch(e)
{
local runEntry = #e.traceback
for(i; 0 .. #e.traceback)
{
if(e.traceback[i].file.startsWith("<croc>.run"))
{
runEntry = i
break
}
}
e.traceback = e.traceback[0 .. runEntry]
if(#e.traceback > 0)
e.traceback = e.traceback[0 .. e.traceback.findIf(\tb -> tb.file.startsWith("<croc>.run"))]
exceptions.rethrow(e)
}
}
@@ -544,7 +550,7 @@ return function main(args: array)
if(params.exec)
return doOneLine(params.execStr)
else if(#params.inputFile)
return doFile(params.inputFile, params.docsEnabled, params.args)
return doFile(params.safe, params.inputFile, params.docsEnabled, params.args)
else
return doInteractive(params.docsEnabled)
}
@@ -566,6 +572,12 @@ word_t _loadLibs(CrocThread* t)
return 0;
}
word_t _loadFileLib(CrocThread* t)
{
croc_vm_loadUnsafeLibs(t, CrocUnsafeLib_File);
return 0;
}
CrocThread* _interruptThread = nullptr;
bool _triggered = false;
@@ -654,6 +666,8 @@ int main(int argc, char** argv)
croc_table_new(t, 0);
croc_function_new(t, "_loadLibs", 2, &_loadLibs, 0);
croc_fielda(t, -2, "_loadLibs");
croc_function_new(t, "_loadFileLib", 0, &_loadFileLib, 0);
croc_fielda(t, -2, "_loadFileLib");
croc_function_new(t, "_setInterruptibleThread", 1, &_setInterruptibleThread, 0);
croc_fielda(t, -2, "_setInterruptibleThread");
croc_function_new(t, "_haltWasTriggered", 0, &_haltWasTriggered, 0);
@@ -1,6 +1,7 @@
#include "croc/api.h"
#include "croc/internal/stack.hpp"
#include "croc/stdlib/helpers/oscompat.hpp"
#include "croc/stdlib/helpers/register.hpp"
#include "croc/types/base.hpp"
@@ -29,6 +30,67 @@ void initModulesLib(CrocThread* t)
croc_cateq(t, -2, 1);
}
croc_fielda(t, -2, "IncludedAddons");
croc_function_new(t, "_existsTime", 1, [](CrocThread* t) -> word_t
{
croc_ex_checkParam(t, 1, CrocType_String);
oscompat::FileInfo info;
if(oscompat::getInfo(t, getCrocstr(t, 1), &info))
{
croc_pushBool(t, true);
croc_pushInt(t, cast(crocint_t)info.modified);
return 2;
}
else
{
croc_pushBool(t, false);
return 1;
}
}, 0);
croc_fielda(t, -2, "_existsTime");
croc_function_new(t, "_getFileContents", 1, [](CrocThread* t) -> word_t
{
croc_ex_checkParam(t, 1, CrocType_String);
auto name = getCrocstr(t, 1);
auto f = oscompat::openFile(t, name, oscompat::FileAccess::Read, oscompat::FileCreate::OpenExisting);
if(f == oscompat::InvalidHandle)
{
croc_pushFormat(t, "Error opening '%.*s' for reading: ", cast(int)name.length, name.ptr);
croc_swapTop(t);
croc_cat(t, 2);
oscompat::throwIOEx(t);
}
auto size = oscompat::seek(t, f, 0, oscompat::Whence::End);
if(size == cast(uint64_t)-1)
oscompat::throwIOEx(t);
if(oscompat::seek(t, f, 0, oscompat::Whence::Begin) == cast(uint64_t)-1)
oscompat::throwIOEx(t);
croc_memblock_new(t, size);
auto ptr = cast(uint8_t*)croc_memblock_getData(t, -1);
uword_t offset = 0;
uword_t remaining = size;
while(remaining > 0)
{
auto bytesRead = oscompat::read(t, f, DArray<uint8_t>::n(ptr + offset, remaining));
if(bytesRead == 0)
croc_eh_throwStd(t, "IOException", "Unexpected end of file");
offset += bytesRead;
remaining -= bytesRead;
}
return 1;
}, 0);
croc_fielda(t, -2, "_getFileContents");
croc_newGlobal(t, "_modulestmp");
registerModuleFromString(t, "modules", modules_croc_text, "modules.croc");
@@ -11,6 +11,8 @@ local path_join = _G.path.join
// Internals
local _setfenv = _modulestmp._setfenv
local _existsTime = _modulestmp._existsTime
local _getFileContents = _modulestmp._getFileContents
local Loading = {}
local Prefixes = {}
@@ -149,16 +151,15 @@ local function loadFiles(name: string)
{
local src = path_join(piece, srcFile)
local bin = src ~ 'o'
local srcExists, binExists = file.exists(src), file.exists(bin)
local srcTime = srcExists ? file.modified(src) : 0
local binTime = binExists ? file.modified(bin) : 0
local srcExists, srcTime = _existsTime(src)
local binExists, binTime = _existsTime(bin);
local fd, loadedName
if(srcExists and (not binExists or srcTime > binTime))
fd, loadedName = compiler.compileModuleEx(file.readTextFile(src), src)
fd, loadedName = compiler.compileModuleEx(text.getCodec('utf-8').decode(_getFileContents(src), 'strict'), src)
else if(binExists)
fd, loadedName = serialization.deserializeModule(stream.MemblockStream(file.readMemblock(bin)))
fd, loadedName = serialization.deserializeModule(stream.MemblockStream(_getFileContents(bin)))
else
continue

0 comments on commit c71276f

Please sign in to comment.