Browse Source

GDScript: Fix crash caused by uninitialized temp stack slots

This adds initialization to every typed temporary stack slot at the
beginning of the function call instead of emitting instructions, since
those might be in a conditional branch and not be called.
George Marques 4 years ago
parent
commit
10a1f64968

+ 5 - 7
modules/gdscript/gdscript_byte_codegen.cpp

@@ -129,12 +129,6 @@ uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type
 		int idx = temporaries.size();
 		pool.push_back(idx);
 		temporaries.push_back(new_temp);
-
-		// First time using this, so adjust to the proper type.
-		if (temp_type != Variant::NIL) {
-			Address addr(Address::TEMPORARY, idx, p_type);
-			write_type_adjust(addr, temp_type);
-		}
 	}
 	int slot = pool.front()->get();
 	pool.pop_front();
@@ -189,8 +183,12 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
 	append(GDScriptFunction::OPCODE_END, 0);
 
 	for (int i = 0; i < temporaries.size(); i++) {
+		int stack_index = i + max_locals + RESERVED_STACK;
 		for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) {
-			opcodes.write[temporaries[i].bytecode_indices[j]] = (i + max_locals + RESERVED_STACK) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+			opcodes.write[temporaries[i].bytecode_indices[j]] = stack_index | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+		}
+		if (temporaries[i].type != Variant::NIL) {
+			function->temporary_slots[stack_index] = temporaries[i].type;
 		}
 	}
 

+ 2 - 0
modules/gdscript/gdscript_function.h

@@ -496,6 +496,8 @@ private:
 	Vector<GDScriptDataType> argument_types;
 	GDScriptDataType return_type;
 
+	Map<int, Variant::Type> temporary_slots;
+
 #ifdef TOOLS_ENABLED
 	Vector<StringName> arg_names;
 	Vector<Variant> default_arg_values;

+ 42 - 0
modules/gdscript/gdscript_vm.cpp

@@ -152,6 +152,44 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
 	return err_text;
 }
 
+void (*type_init_function_table[])(Variant *) = {
+	nullptr, // NIL (shouldn't be called).
+	&VariantInitializer<bool>::init, // BOOL.
+	&VariantInitializer<int64_t>::init, // INT.
+	&VariantInitializer<double>::init, // FLOAT.
+	&VariantInitializer<String>::init, // STRING.
+	&VariantInitializer<Vector2>::init, // VECTOR2.
+	&VariantInitializer<Vector2i>::init, // VECTOR2I.
+	&VariantInitializer<Rect2>::init, // RECT2.
+	&VariantInitializer<Rect2i>::init, // RECT2I.
+	&VariantInitializer<Vector3>::init, // VECTOR3.
+	&VariantInitializer<Vector3i>::init, // VECTOR3I.
+	&VariantInitializer<Transform2D>::init, // TRANSFORM2D.
+	&VariantInitializer<Plane>::init, // PLANE.
+	&VariantInitializer<Quat>::init, // QUAT.
+	&VariantInitializer<AABB>::init, // AABB.
+	&VariantInitializer<Basis>::init, // BASIS.
+	&VariantInitializer<Transform>::init, // TRANSFORM.
+	&VariantInitializer<Color>::init, // COLOR.
+	&VariantInitializer<StringName>::init, // STRING_NAME.
+	&VariantInitializer<NodePath>::init, // NODE_PATH.
+	&VariantInitializer<RID>::init, // RID.
+	&VariantTypeAdjust<Object *>::adjust, // OBJECT.
+	&VariantInitializer<Callable>::init, // CALLABLE.
+	&VariantInitializer<Signal>::init, // SIGNAL.
+	&VariantInitializer<Dictionary>::init, // DICTIONARY.
+	&VariantInitializer<Array>::init, // ARRAY.
+	&VariantInitializer<PackedByteArray>::init, // PACKED_BYTE_ARRAY.
+	&VariantInitializer<PackedInt32Array>::init, // PACKED_INT32_ARRAY.
+	&VariantInitializer<PackedInt64Array>::init, // PACKED_INT64_ARRAY.
+	&VariantInitializer<PackedFloat32Array>::init, // PACKED_FLOAT32_ARRAY.
+	&VariantInitializer<PackedFloat64Array>::init, // PACKED_FLOAT64_ARRAY.
+	&VariantInitializer<PackedStringArray>::init, // PACKED_STRING_ARRAY.
+	&VariantInitializer<PackedVector2Array>::init, // PACKED_VECTOR2_ARRAY.
+	&VariantInitializer<PackedVector3Array>::init, // PACKED_VECTOR3_ARRAY.
+	&VariantInitializer<PackedColorArray>::init, // PACKED_COLOR_ARRAY.
+};
+
 #if defined(__GNUC__)
 #define OPCODES_TABLE                                \
 	static const void *switch_table_ops[] = {        \
@@ -491,6 +529,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 
 	memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
 
+	for (const Map<int, Variant::Type>::Element *E = temporary_slots.front(); E; E = E->next()) {
+		type_init_function_table[E->get()](&stack[E->key()]);
+	}
+
 	String err_text;
 
 #ifdef DEBUG_ENABLED