shithub: femtolisp

Download patch

ref: d60399e18345e69419489f201f27f19f1a5616b2
parent: 7fcae265252c0a29cf2a4b0c1474b35e7ad39619
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Dec 25 01:46:07 EST 2024

validate bytecode data - fail on invalid instructions

Also produce a compile-time warning if an opcode isn't handled
by the logic, to avoid boxl style problems in the future.

--- a/flisp.c
+++ b/flisp.c
@@ -1973,7 +1973,7 @@
 	cvalue_t *arr = (cvalue_t*)ptr(args[0]);
 	cv_pin(arr);
 	char *data = cv_data(arr);
-	uint32_t ms;
+	int ms;
 	if((uint8_t)data[4] >= N_OPCODES){
 		// read syntax, shifted 48 for compact text representation
 		size_t i, sz = cv_len(arr);
@@ -1988,6 +1988,8 @@
 	}
 	ms = compute_maxstack((uint8_t*)data, cv_len(arr));
 #endif
+	if(ms < 0)
+		lerrorf(FL(ArgError), "invalid bytecode");
 	PUT_INT32(data, ms);
 	function_t *fn = alloc_words(4);
 	value_t fv = tagptr(fn, TAG_FUNCTION);
--- a/gen.lsp
+++ b/gen.lsp
@@ -111,7 +111,7 @@
       (lms ())
       (i 0))
   (begin
-    (io-write c-header "enum {\n")
+    (io-write c-header "typedef enum {\n")
     (for-each-n
       (λ (cop lop argc f)
         (begin
@@ -125,7 +125,7 @@
           (set! lms (cons f lms))
           (set! i (1+ i))))
       opcodes 4)
-    (io-write c-header "\tN_OPCODES\n};\n\n")
+    (io-write c-header "\tN_OPCODES\n}opcode_t;\n\n")
     (io-write c-header "extern const Builtin builtins[N_OPCODES];\n")
     (io-close c-header)
     (io-write c-code "#include \"flisp.h\"\n\n")
--- a/maxstack.inc
+++ b/maxstack.inc
@@ -1,13 +1,16 @@
-static uint32_t
+static int
 compute_maxstack(uint8_t *code, size_t len)
 {
 	uint8_t *ip = code+4, *end = code+len;
-	uint32_t i, n, sp = 0, maxsp = 0;
+	int i, n, sp = 0, maxsp = 0;
 
 	while(ip < end){
 		if((int32_t)sp > (int32_t)maxsp)
 			maxsp = sp;
-		switch(*ip++){
+		opcode_t op = *ip++;
+		if(op >= N_OPCODES)
+			return -1;
+		switch(op){
 		case OP_LOADA: case OP_LOADI8: case OP_LOADV: case OP_LOADG:
 			ip++; // fallthrough
 		case OP_LOADA0: case OP_LOADA1:
@@ -142,8 +145,20 @@
 			SWAP_INT32(ip);
 			ip += 4;
 			break;
+
+		case OP_CAR: case OP_CDR: case OP_CADR:
+		case OP_NOT: case OP_NEG:
+		case OP_CONSP: case OP_ATOMP: case OP_SYMBOLP:
+		case OP_NULLP: case OP_BOOLEANP: case OP_NUMBERP:
+		case OP_FIXNUMP: case OP_BOUNDP: case OP_BUILTINP:
+		case OP_FUNCTIONP: case OP_VECTORP:
+			break;
+
+		case OP_EOF_OBJECT: case N_OPCODES:
+			return -1;
 		}
 	}
 	assert(ip == end);
+	assert(maxsp >= 0);
 	return maxsp+4;
 }
--- a/opcodes.h
+++ b/opcodes.h
@@ -1,4 +1,4 @@
-enum {
+typedef enum {
 	OP_LOADA0,
 	OP_LOADA1,
 	OP_LOADV,
@@ -95,6 +95,6 @@
 	OP_LOADVOID,
 	OP_EOF_OBJECT,
 	N_OPCODES
-};
+}opcode_t;
 
 extern const Builtin builtins[N_OPCODES];