Browse Source

Fixed a string conversion list recursion bug. Added a way to set max allowed c recursive calls in order to fix user generated infinite loop issues.

Marco Bambini 8 years ago
parent
commit
3c8cfec597
3 changed files with 19 additions and 4 deletions
  1. 7 2
      src/runtime/gravity_core.c
  2. 11 2
      src/runtime/gravity_vm.c
  3. 1 0
      src/shared/gravity_value.h

+ 7 - 2
src/runtime/gravity_core.c

@@ -198,8 +198,13 @@ static inline gravity_value_t convert_list2string (gravity_vm *vm, gravity_list_
 	uint32_t count = (uint32_t) marray_size(list->array);
 	for (uint32_t i=0; i<count; ++i) {
 		gravity_value_t value = marray_get(list->array, i);
-		gravity_value_t value2 = convert_value2string(vm, value);
-		gravity_string_t *string = VALUE_ISA_VALID(value2) ? VALUE_AS_STRING(value2) : NULL;
+        gravity_string_t *string;
+        if (VALUE_ISA_LIST(value) && (VALUE_AS_LIST(value) == list)) {
+            string = NULL;
+        } else {
+			gravity_value_t value2 = convert_value2string(vm, value);
+            string = VALUE_ISA_VALID(value2) ? VALUE_AS_STRING(value2) : NULL;
+        }
 		
 		char *s1 = (string) ? string->s : "N/A";
 		uint32_t len1 = (string) ? string->len : 3;

+ 11 - 2
src/runtime/gravity_vm.c

@@ -36,6 +36,8 @@ struct gravity_vm {
 	uint32_t			pc;									// program counter
 	double				time;								// useful timer for the main function
 	bool				aborted;							// set when VM has generated a runtime error
+    uint32_t            maxncalls;                          // maximum number of nested c calls
+    uint32_t            nccalls;                            // current number of nested c calls
 	
 	// anonymous names
 	uint32_t			nanon;								// counter for anonymous classes (used in object_bind)
@@ -195,11 +197,12 @@ static inline bool gravity_check_stack (gravity_vm *vm, gravity_fiber_t *fiber,
 	uint32_t stack_size = (uint32_t)(fiber->stacktop - fiber->stack);
 	uint32_t stack_needed = MAXNUM(stack_size + rneeds, DEFAULT_MINSTACK_SIZE);
 	if (fiber->stackalloc >= stack_needed) return true;
+	gravity_value_t *old_stack = fiber->stack;
 	
 	// perform stack reallocation (power_of2_ceil returns 0 if argument is bigger than 2^31)
 	uint32_t new_size = power_of2_ceil(fiber->stackalloc + stack_needed);
-	gravity_value_t *old_stack = fiber->stack;
-    void *ptr = (new_size) ? mem_realloc(fiber->stack, sizeof(gravity_value_t) * new_size) : NULL;
+    bool size_condition = (new_size && (uint64_t)new_size >= (uint64_t)(fiber->stackalloc + stack_needed) && ((sizeof(gravity_value_t) * new_size) < SIZE_MAX));
+    void *ptr = (size_condition) ? mem_realloc(fiber->stack, sizeof(gravity_value_t) * new_size) : NULL;
     if (!ptr) {
         // restore stacktop to previous state
         fiber->stacktop -= rneeds;
@@ -1295,6 +1298,7 @@ gravity_vm *gravity_vm_new (gravity_delegate_t *delegate/*, uint32_t context_siz
 	
 	// allocate default fiber
 	vm->fiber = gravity_fiber_new(vm, NULL, 0, 0);
+    vm->maxncalls = MAX_CCALLS;
 	
 	vm->pc = 0;
 	vm->delegate = delegate;
@@ -1501,7 +1505,10 @@ bool gravity_vm_runclosure (gravity_vm *vm, gravity_closure_t *closure, gravity_
 	bool result = false;
 	switch (f->tag) {
 		case EXEC_TYPE_NATIVE:
+            ++vm->nccalls;
+            if (vm->nccalls > vm->maxncalls) RUNTIME_ERROR("Maximum number of nested C calls reached (%d).", vm->maxncalls);
 			result = gravity_vm_exec(vm);
+            --vm->nccalls;
 			break;
 			
 		case EXEC_TYPE_INTERNAL:
@@ -1630,6 +1637,7 @@ gravity_value_t gravity_vm_get (gravity_vm *vm, const char *key) {
 		if (strcmp(key, "gcminthreshold") == 0) return VALUE_FROM_INT(vm->gcminthreshold);
 		if (strcmp(key, "gcthreshold") == 0) return VALUE_FROM_INT(vm->gcthreshold);
 		if (strcmp(key, "gcratio") == 0) return VALUE_FROM_FLOAT(vm->gcratio);
+        if (strcmp(key, "maxncalls") == 0) return VALUE_FROM_INT(vm->maxncalls);
 	}
 	return VALUE_FROM_NULL;
 }
@@ -1640,6 +1648,7 @@ bool gravity_vm_set (gravity_vm *vm, const char *key, gravity_value_t value) {
 		if ((strcmp(key, "gcminthreshold") == 0) && VALUE_ISA_INT(value)) {vm->gcminthreshold = VALUE_AS_INT(value); return true;}
 		if ((strcmp(key, "gcthreshold") == 0) && VALUE_ISA_INT(value)) {vm->gcthreshold = VALUE_AS_INT(value); return true;}
 		if ((strcmp(key, "gcratio") == 0) && VALUE_ISA_FLOAT(value)) {vm->gcratio = VALUE_AS_FLOAT(value); return true;}
+        if ((strcmp(key, "maxncalls") == 0) && VALUE_ISA_INT(value)) {vm->maxncalls = (uint32_t)VALUE_AS_INT(value); return true;}
 	}
 	return false;
 }

+ 1 - 0
src/shared/gravity_value.h

@@ -112,6 +112,7 @@ extern "C" {
 #define MAX_FIELDSxFLUSH					64			// used in list/map serialization
 #define MAX_IVARS							768			// 2^10 - 2^8
 #define MAX_ALLOCATION                      4194304     // 1024 * 1024 * 4 (about 4 millions entry)
+#define MAX_CCALLS                          100         // default maximum number of nested C calls
 
 #define DEFAULT_CONTEXT_SIZE				256			// default VM context entries (can grow)
 #define DEFAULT_MINSTRING_SIZE				64			// minimum string allocation size