Allow configurable recursion depth and raise exception when exceeded

This commit is contained in:
K. Lange 2021-07-22 21:42:39 +09:00
parent 194b45c25d
commit f979321141
4 changed files with 32 additions and 4 deletions

View File

@ -762,7 +762,8 @@ int main(int argc, char * argv[]) {
int moduleAsMain = 0;
int inspectAfter = 0;
int opt;
while ((opt = getopt(argc, argv, "+:c:C:dgGim:rstTMSV-:")) != -1) {
int maxDepth = -1;
while ((opt = getopt(argc, argv, "+:c:C:dgGim:rR:stTMSV-:")) != -1) {
switch (opt) {
case 'c':
runCmd = optarg;
@ -804,6 +805,9 @@ int main(int argc, char * argv[]) {
case 'r':
enableRline = 0;
break;
case 'R':
maxDepth = atoi(optarg);
break;
case 'M':
return runString(argv,0,"import kuroko; print(kuroko.module_paths)\n");
case 'V':
@ -834,6 +838,7 @@ int main(int argc, char * argv[]) {
" -i Enter repl after a running -c, -m, or FILE.\n"
" -m mod Run a module as a script.\n"
" -r Disable complex line editing in the REPL.\n"
" -R depth Set maximum recursion depth.\n"
" -s Debug output from the scanner/tokenizer.\n"
" -t Disassemble instructions as they are exceuted.\n"
" -T Write call trace file.\n"
@ -861,6 +866,10 @@ _finishArgs:
findInterpreter(argv);
krk_initVM(flags);
if (maxDepth != -1) {
krk_setMaximumRecursionDepth(maxDepth);
}
#ifndef KRK_DISABLE_DEBUG
krk_debug_registerCallback(debuggerHook);
#endif

View File

@ -225,6 +225,7 @@ typedef struct KrkVM {
KrkThreadState * threads; /**< Invasive linked list of all VM threads. */
FILE * callgrindFile; /**< File to write unprocessed callgrind data to. */
size_t maximumCallDepth; /**< Maximum recursive call depth. */
} KrkVM;
/* Thread-specific flags */
@ -824,3 +825,7 @@ extern KrkValue krk_operator_lt(KrkValue,KrkValue);
*/
extern KrkValue krk_operator_gt(KrkValue,KrkValue);
/**
* @brief Set the maximum recursion call depth.
*/
extern void krk_setMaximumRecursionDepth(size_t maxDepth);

View File

@ -67,7 +67,7 @@ KRK_FUNC(current_thread,{
static volatile int _threadLock = 0;
static void * _startthread(void * _threadObj) {
memset(&krk_currentThread, 0, sizeof(KrkThreadState));
krk_currentThread.frames = calloc(KRK_CALL_FRAMES_MAX,sizeof(KrkCallFrame));
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
vm.globalFlags |= KRK_GLOBAL_THREADS;
_obtain_lock(_threadLock);
if (vm.threads->next) {

View File

@ -734,7 +734,10 @@ _finishKwarg:
return 2;
}
if (unlikely(krk_currentThread.frameCount == KRK_CALL_FRAMES_MAX)) goto _errorAfterKeywords;
if (unlikely(krk_currentThread.frameCount == vm.maximumCallDepth)) {
krk_runtimeError(vm.exceptions->baseException, "maximum recursion depth exceeded");
goto _errorAfterKeywords;
}
KrkCallFrame * frame = &krk_currentThread.frames[krk_currentThread.frameCount++];
frame->closure = closure;
@ -1143,12 +1146,23 @@ KRK_FUNC(unload,{
}
})
void krk_setMaximumRecursionDepth(size_t maxDepth) {
vm.maximumCallDepth = maxDepth;
KrkThreadState * thread = vm.threads;
while (thread) {
thread->frames = realloc(thread->frames, maxDepth * sizeof(KrkCallFrame));
thread = thread->next;
}
}
void krk_initVM(int flags) {
vm.globalFlags = flags & 0xFF00;
vm.maximumCallDepth = KRK_CALL_FRAMES_MAX;
/* Reset current thread */
krk_resetStack();
krk_currentThread.frames = calloc(KRK_CALL_FRAMES_MAX,sizeof(KrkCallFrame));
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.flags = flags & 0x00FF;
krk_currentThread.module = NULL;
vm.threads = &krk_currentThread;