瀏覽代碼

Merge pull request #48793 from vnen/gdscript-fix-temp-type-adjust

GDScript: Fix crash caused by uninitialized temp stack slots
Rémi Verschelde 4 年之前
父節點
當前提交
2fcfc83da9
共有 3 個文件被更改,包括 49 次插入7 次删除
  1. 5 7
      modules/gdscript/gdscript_byte_codegen.cpp
  2. 2 0
      modules/gdscript/gdscript_function.h
  3. 42 0
      modules/gdscript/gdscript_vm.cpp

+ 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

@@ -497,6 +497,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[] = {        \
@@ -492,6 +530,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