Explorar o código

Added a check that makes sure RTTI plain fields are POD, so we don't cause data corruption by accidentially memcpying something that can't be memcpyed properly

Marko Pintera %!s(int64=13) %!d(string=hai) anos
pai
achega
d220a6bf24

+ 0 - 3
CamelotClient/CamelotClient.cpp

@@ -1,6 +1,3 @@
-// CamelotClient.cpp : Defines the entry point for the console application.
-//
-
 #include "stdafx.h"
 #include <windows.h>
 

+ 2 - 0
CamelotRenderer/Include/CmDepthStencilState.h

@@ -44,6 +44,8 @@ namespace CamelotEngine
 		CompareFunction backStencilComparisonFunc;
 	};
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(DEPTH_STENCIL_STATE_DESC);
+
 	// TODO Low priority - Write doc explaining various states
 	class CM_EXPORT DepthStencilState : public Resource
 	{

+ 2 - 0
CamelotRenderer/Include/CmMeshDataRTTI.h

@@ -66,6 +66,8 @@ namespace CamelotEngine
 		}
 	};
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(MeshData::SubMeshData);
+
 	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, IReflectable, MeshDataRTTI>
 	{
 	private:

+ 2 - 0
CamelotRenderer/Include/CmRasterizerStateRTTI.h

@@ -7,6 +7,8 @@
 
 namespace CamelotEngine
 {
+	CM_ALLOW_MEMCPY_SERIALIZATION(RASTERIZER_STATE_DESC);
+
 	class CM_EXPORT RasterizerStateRTTI : public RTTIType<RasterizerState, IReflectable, RasterizerStateRTTI>
 	{
 	private:

+ 2 - 0
CamelotRenderer/Include/CmSamplerStateRTTI.h

@@ -7,6 +7,8 @@
 
 namespace CamelotEngine
 {
+	CM_ALLOW_MEMCPY_SERIALIZATION(SAMPLER_STATE_DESC);
+
 	class CM_EXPORT SamplerStateRTTI : public RTTIType<SamplerState, IReflectable, SamplerStateRTTI>
 	{
 	private:

+ 2 - 0
CamelotRenderer/Include/CmVertexDeclarationRTTI.h

@@ -7,6 +7,8 @@
 
 namespace CamelotEngine
 {
+	CM_ALLOW_MEMCPY_SERIALIZATION(VertexElement);
+
 	class VertexDeclarationRTTI : public RTTIType<VertexDeclaration, IReflectable, VertexDeclarationRTTI>
 	{
 	private:

+ 0 - 3
CamelotRenderer/TODO.txt

@@ -160,9 +160,6 @@ Low priority TODO:
  - D3D9Texture::createTextureResources is commented out at the moment. It gets called on device reset, and at that point I should reload texture resources.
   - I should probably keep all resources by DX managed. OpenGL apparently keeps a mirror of all its resources anyway.
  - Device reset and resource re-loading in general
- - In RTTIType it is possible to add a non-plain data type using addPlainField. This can cause memory corruption issues
-   if pointer is saved/loaded as a plain field. I need to add a check that ensures the type is POD. 
-   See: http://www.boost.org/doc/libs/1_51_0/boost/mpi/datatype.hpp for a possible implementation of a compile time check.
  - Fix up WorkQueue as it doesn't lock when initializing, to make sure threads are actually started before returning
  - CPU reading or writing to a render texture in OpenGL is not supported. (CmGLHardwarePixelBuffer::upload/download). 
  - When saving a resource, make sure resource is properly loaded before saving

+ 1 - 0
CamelotUtility/CamelotUtility.vcxproj

@@ -193,6 +193,7 @@
     <ClInclude Include="Include\CmRTTIField.h" />
     <ClInclude Include="Include\CmRTTIManagedDataBlockField.h" />
     <ClInclude Include="Include\CmRTTIPlainField.h" />
+    <ClInclude Include="Include\CmRTTIPrerequisites.h" />
     <ClInclude Include="Include\CmRTTIReflectableField.h" />
     <ClInclude Include="Include\CmRTTIReflectablePtrField.h" />
     <ClInclude Include="Include\CmRTTIType.h" />

+ 3 - 0
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -207,6 +207,9 @@
     <ClInclude Include="Include\CmUtil.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmRTTIPrerequisites.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Include\CmAxisAlignedBox.cpp">

+ 1 - 0
CamelotUtility/Include/CmColor.h

@@ -329,6 +329,7 @@ namespace CamelotEngine {
 	/** @} */
 	/** @} */
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(Color);
 } // namespace
 
 #endif

+ 2 - 0
CamelotUtility/Include/CmMatrix3.h

@@ -268,5 +268,7 @@ namespace CamelotEngine
     };
 	/** @} */
 	/** @} */
+
+	CM_ALLOW_MEMCPY_SERIALIZATION(Matrix3);
 }
 #endif

+ 1 - 0
CamelotUtility/Include/CmMatrix4.h

@@ -656,5 +656,6 @@ namespace CamelotEngine
 	/** @} */
 	/** @} */
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(Matrix4);
 }
 #endif

+ 3 - 1
CamelotUtility/Include/CmPrerequisitesUtil.h

@@ -70,4 +70,6 @@ THE SOFTWARE
 // Forward declarations
 #include "CmFwdDeclUtil.h"
 
-#include "CmString.h"
+#include "CmString.h"
+
+#include "CmRTTIPrerequisites.h"

+ 1 - 96
CamelotUtility/Include/CmRTTIField.h

@@ -5,6 +5,7 @@
 #include <boost/function.hpp>
 #include <boost/any.hpp>
 #include <boost/static_assert.hpp>
+#include <type_traits>
 
 #include "CmPrerequisitesUtil.h"
 #include "CmIReflectable.h"
@@ -16,102 +17,6 @@ namespace CamelotEngine
 	class RTTITypeBase;
 	struct RTTIField;
 
-	/**
-	* @brief	Helper method when serializing known data types that have valid
-	* 			SerializableSimpleType specializations.
-	* 			
-	*			Returns the size of the element. If elements serializable type is 
-	*			specialized with hasDynamicSize == true, the dynamic size is calculated, 
-	*			otherwise sizeof() is used.
-	 */
-	template<class ElemType>
-	UINT32 rttiGetElemSize(ElemType& data)
-	{
-		if(SerializableSimpleType<ElemType>::hasDynamicSize == 1)
-			return SerializableSimpleType<ElemType>::getDynamicSize(data);
-		else
-			return sizeof(ElemType);
-	}
-
-	/**
-	 * @brief	Helper method when serializing known data types that have valid
-	 * 			SerializableSimpleType specializations.
-	 * 			
-	 *			Writes the specified data into memory, advances the memory pointer by the
-	 *			bytes written and returns pointer to new memory.
-	 */
-	template<class ElemType>
-	char* rttiWriteElem(ElemType& data, char* memory)
-	{
-		SerializableSimpleType<ElemType>::toMemory(data, memory);
-
-		return memory + rttiGetElemSize(data);
-	}
-
-	/**
-	 * @brief	Helper method when serializing known data types that have valid
-	 * 			SerializableSimpleType specializations.
-	 * 			
-	 *			Reads the specified data into memory, advances the memory pointer by the
-	 *			bytes read and returns pointer to new memory.
-	 */
-	template<class ElemType>
-	char* rttiReadElem(ElemType& data, char* memory)
-	{
-		SerializableSimpleType<ElemType>::fromMemory(data, memory);
-
-		return memory + rttiGetElemSize(data);
-	}
-
-	template<class T>
-	struct SerializableSimpleType 
-	{ 
-		//BOOST_STATIC_ASSERT_MSG(sizeof(T) == 0, // We need this hacky check, otherwise if we only use "false" compiler will evaluate the template and trigger this message 
-		//	"Provided data type isn't marked as serializable. Declare SerializableSimpleType template specialization to define a unique ID and needed methods for the type.");
-
-		enum { id = 0 }; 
-		enum { hasDynamicSize = 0 };
-
-		static void toMemory(T& data, char* memory)	
-		{ 
-			memcpy(memory, &data, sizeof(T)); 
-		}
-
-		static void fromMemory(T& data, char* memory)
-		{
-			memcpy(&data, memory, sizeof(T)); 
-		}
-
-		static UINT32 getDynamicSize(T& data)
-		{ 
-			assert(false); 
-			return sizeof(T);
-		}
-	};
-
-#define CM_SERIALIZABLE_SIMPLE_TYPE(type, type_id)				\
-	template<> struct SerializableSimpleType<##type##>			\
-	{	enum { id=##type_id }; enum { hasDynamicSize = 0 };		\
-	static void toMemory(##type##& data, char* memory)		\
-	{ memcpy(memory, &data, sizeof(##type##)); }			\
-	static void fromMemory(##type##& data, char* memory)	\
-	{ memcpy(&data, memory, sizeof(##type##)); }			\
-	static UINT32 getDynamicSize(##type##& data)			\
-	{ assert(false); return sizeof(##type##); }				\
-	}; 
-
-	CM_SERIALIZABLE_SIMPLE_TYPE(UINT8, 1);
-	CM_SERIALIZABLE_SIMPLE_TYPE(UINT16, 2);
-	CM_SERIALIZABLE_SIMPLE_TYPE(UINT32, 3);
-	CM_SERIALIZABLE_SIMPLE_TYPE(UINT64, 4);
-	CM_SERIALIZABLE_SIMPLE_TYPE(INT8, 5);
-	CM_SERIALIZABLE_SIMPLE_TYPE(INT16, 6);
-	CM_SERIALIZABLE_SIMPLE_TYPE(INT32, 7);
-	CM_SERIALIZABLE_SIMPLE_TYPE(INT64, 8);
-	CM_SERIALIZABLE_SIMPLE_TYPE(float, 9);
-	CM_SERIALIZABLE_SIMPLE_TYPE(double, 10);
-	CM_SERIALIZABLE_SIMPLE_TYPE(bool, 11);
-		
 	/**
 	 * @brief	Strings need to copy their data in a slightly more intricate way than just memcpy.
 	 */

+ 89 - 0
CamelotUtility/Include/CmRTTIPrerequisites.h

@@ -0,0 +1,89 @@
+#pragma once
+
+namespace CamelotEngine
+{
+	/**
+	* @brief	Helper method when serializing known data types that have valid
+	* 			SerializableSimpleType specializations.
+	* 			
+	*			Returns the size of the element. If elements serializable type is 
+	*			specialized with hasDynamicSize == true, the dynamic size is calculated, 
+	*			otherwise sizeof() is used.
+	 */
+	template<class ElemType>
+	UINT32 rttiGetElemSize(ElemType& data)
+	{
+		if(SerializableSimpleType<ElemType>::hasDynamicSize == 1)
+			return SerializableSimpleType<ElemType>::getDynamicSize(data);
+		else
+			return sizeof(ElemType);
+	}
+
+	/**
+	 * @brief	Helper method when serializing known data types that have valid
+	 * 			SerializableSimpleType specializations.
+	 * 			
+	 *			Writes the specified data into memory, advances the memory pointer by the
+	 *			bytes written and returns pointer to new memory.
+	 */
+	template<class ElemType>
+	char* rttiWriteElem(ElemType& data, char* memory)
+	{
+		SerializableSimpleType<ElemType>::toMemory(data, memory);
+
+		return memory + rttiGetElemSize(data);
+	}
+
+	/**
+	 * @brief	Helper method when serializing known data types that have valid
+	 * 			SerializableSimpleType specializations.
+	 * 			
+	 *			Reads the specified data into memory, advances the memory pointer by the
+	 *			bytes read and returns pointer to new memory.
+	 */
+	template<class ElemType>
+	char* rttiReadElem(ElemType& data, char* memory)
+	{
+		SerializableSimpleType<ElemType>::fromMemory(data, memory);
+
+		return memory + rttiGetElemSize(data);
+	}
+
+	template<class T>
+	struct SerializableSimpleType 
+	{ 
+		static_assert(std::is_pod<T>::value, 
+			"Serializable type isn't plain-old-data. You need to specialize SerializableSimpleType template in order to serialize this type. "\
+			" (Or call CM_MAKE_SERIALIZABLE(type) macro if you are sure the type can be properly serialized using just memcpy.)");
+
+		enum { id = 0 }; 
+		enum { hasDynamicSize = 0 };
+
+		static void toMemory(T& data, char* memory)	
+		{ 
+			memcpy(memory, &data, sizeof(T)); 
+		}
+
+		static void fromMemory(T& data, char* memory)
+		{
+			memcpy(&data, memory, sizeof(T)); 
+		}
+
+		static UINT32 getDynamicSize(T& data)
+		{ 
+			assert(false); 
+			return sizeof(T);
+		}
+	};
+
+#define CM_ALLOW_MEMCPY_SERIALIZATION(type)				\
+	template<> struct SerializableSimpleType<##type##>			\
+	{	enum { id=0 }; enum { hasDynamicSize = 0 };		\
+	static void toMemory(##type##& data, char* memory)		\
+	{ memcpy(memory, &data, sizeof(##type##)); }			\
+	static void fromMemory(##type##& data, char* memory)	\
+	{ memcpy(&data, memory, sizeof(##type##)); }			\
+	static UINT32 getDynamicSize(##type##& data)			\
+	{ assert(false); return sizeof(##type##); }				\
+	}; 
+}

+ 1 - 1
CamelotUtility/Include/CmVector2.h

@@ -34,7 +34,6 @@ THE SOFTWARE.
 
 namespace CamelotEngine
 {
-
 	/** \addtogroup Core
 	*  @{
 	*/
@@ -569,5 +568,6 @@ namespace CamelotEngine
 	/** @} */
 	/** @} */
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(Vector2);
 }
 #endif

+ 1 - 1
CamelotUtility/Include/CmVector3.h

@@ -34,7 +34,6 @@ THE SOFTWARE.
 
 namespace CamelotEngine
 {
-
 	/** \addtogroup Core
 	*  @{
 	*/
@@ -795,5 +794,6 @@ namespace CamelotEngine
 	/** @} */
 	/** @} */
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(Vector3);
 }
 #endif

+ 1 - 1
CamelotUtility/Include/CmVector4.h

@@ -33,7 +33,6 @@ THE SOFTWARE.
 
 namespace CamelotEngine
 {
-
 	/** \addtogroup Core
 	*  @{
 	*/
@@ -409,6 +408,7 @@ namespace CamelotEngine
 	/** @} */
 	/** @} */
 
+	CM_ALLOW_MEMCPY_SERIALIZATION(Vector4);
 }
 #endif