Device/Renderer: Work arounds for MemorySanitizer false-positives

MemorySanitizer has no visibility into writes performed by JIT'd code.

If we have built the project with the MemorySanitizer enabled, memset the Triangle and Primitive structs so the sanitizer has a write to see.

This is only cleared in MemorySanitizer enabled builds, as this adds a non negligable cost to Renderer construction.

Bug: chromium:998457
Change-Id: I3b4f9e48783c6e8a1109a578988567b0a42eb1f9
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35688
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 551290a..2588a2e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1724,6 +1724,7 @@
     ${VULKAN_DIR}/*.cpp
     ${VULKAN_DIR}/*.h
     ${VULKAN_DIR}/*.hpp
+    ${SOURCE_DIR}/System/Build.hpp
     ${SOURCE_DIR}/System/CPUID.cpp
     ${SOURCE_DIR}/System/CPUID.hpp
     ${SOURCE_DIR}/System/Configurator.cpp
diff --git a/build/Visual Studio 15 2017 Win64/SwiftShader.vcxproj b/build/Visual Studio 15 2017 Win64/SwiftShader.vcxproj
index 34cf13d..500e5e2 100644
--- a/build/Visual Studio 15 2017 Win64/SwiftShader.vcxproj
+++ b/build/Visual Studio 15 2017 Win64/SwiftShader.vcxproj
@@ -166,6 +166,7 @@
     <ClInclude Include="$(SolutionDir)src\Renderer\LRUCache.hpp" />

     <ClCompile Include="$(SolutionDir)src\Renderer\Matrix.cpp" />

     <ClInclude Include="$(SolutionDir)src\Renderer\Matrix.hpp" />

+    <ClInclude Include="$(SolutionDir)src\Renderer\Memset.hpp" />

     <ClCompile Include="$(SolutionDir)src\Renderer\PixelProcessor.cpp" />

     <ClInclude Include="$(SolutionDir)src\Renderer\PixelProcessor.hpp" />

     <ClCompile Include="$(SolutionDir)src\Renderer\Plane.cpp" />

diff --git a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
index fd05c89..490ef6a 100644
--- a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
+++ b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj
@@ -204,6 +204,7 @@
     <ClInclude Include="$(SolutionDir)src\Device\LRUCache.hpp" />

     <ClCompile Include="$(SolutionDir)src\Device\Matrix.cpp" />

     <ClInclude Include="$(SolutionDir)src\Device\Matrix.hpp" />

+    <ClInclude Include="$(SolutionDir)src\Device\Memset.hpp" />

     <ClCompile Include="$(SolutionDir)src\Device\PixelProcessor.cpp" />

     <ClInclude Include="$(SolutionDir)src\Device\PixelProcessor.hpp" />

     <ClCompile Include="$(SolutionDir)src\Device\Plane.cpp" />

@@ -253,6 +254,7 @@
     <ClInclude Include="$(SolutionDir)src\Pipeline\VertexRoutine.hpp" />

     <ClCompile Include="$(SolutionDir)src\System\CPUID.cpp" />

     <ClInclude Include="$(SolutionDir)src\System\CPUID.hpp" />

+    <ClInclude Include="$(SolutionDir)src\System\Build.hpp" />

     <ClCompile Include="$(SolutionDir)src\System\Configurator.cpp" />

     <ClInclude Include="$(SolutionDir)src\System\Configurator.hpp" />

     <ClCompile Include="$(SolutionDir)src\System\Debug.cpp" />

diff --git a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
index c09db0c..27cea4f 100644
--- a/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
+++ b/build/Visual Studio 15 2017 Win64/libvk_swiftshader.vcxproj.filters
@@ -225,6 +225,9 @@
     <ClInclude Include="$(SolutionDir)src\Device\Matrix.hpp">

       <Filter>src\Device</Filter>

     </ClInclude>

+    <ClInclude Include="$(SolutionDir)src\Device\Memset.hpp">

+      <Filter>src\Device</Filter>

+    </ClInclude>

     <ClInclude Include="$(SolutionDir)src\Device\PixelProcessor.hpp">

       <Filter>src\Device</Filter>

     </ClInclude>

@@ -306,6 +309,9 @@
     <ClInclude Include="$(SolutionDir)src\Pipeline\VertexRoutine.hpp">

       <Filter>src\Pipeline</Filter>

     </ClInclude>

+    <ClInclude Include="$(SolutionDir)src\System\Build.hpp">

+      <Filter>src\System</Filter>

+    </ClInclude>

     <ClInclude Include="$(SolutionDir)src\System\CPUID.hpp">

       <Filter>src\System</Filter>

     </ClInclude>

diff --git a/src/Device/BUILD.gn b/src/Device/BUILD.gn
index fa7d6b4..2a61fff9 100644
--- a/src/Device/BUILD.gn
+++ b/src/Device/BUILD.gn
@@ -30,6 +30,7 @@
     "ETC_Decoder.hpp",
     "Matrix.cpp",
     "Matrix.hpp",
+    "Memset.hpp",
     "PixelProcessor.cpp",
     "PixelProcessor.hpp",
     "Plane.cpp",
diff --git a/src/Device/Blitter.hpp b/src/Device/Blitter.hpp
index 849bcc2..6e20a3a 100644
--- a/src/Device/Blitter.hpp
+++ b/src/Device/Blitter.hpp
@@ -15,6 +15,7 @@
 #ifndef sw_Blitter_hpp
 #define sw_Blitter_hpp
 
+#include "Memset.hpp"
 #include "RoutineCache.hpp"
 #include "Reactor/Reactor.hpp"
 #include "Vulkan/VkFormat.h"
diff --git a/src/Device/LRUCache.hpp b/src/Device/LRUCache.hpp
index e4ec2b3..4b50a57 100644
--- a/src/Device/LRUCache.hpp
+++ b/src/Device/LRUCache.hpp
@@ -17,7 +17,6 @@
 
 #include "System/Math.hpp"
 
-#include <cstring>
 #include <type_traits>
 #include <unordered_map>
 
@@ -71,32 +70,6 @@
 		std::unordered_map<Key, Data, Hasher> constCache;
 	};
 
-	// Helper class for clearing the memory of objects at construction.
-	// Useful as the first base class of cache keys which may contain padding bytes or bits otherwise left uninitialized.
-	template<class T>
-	struct Memset
-	{
-		Memset(T *object, int val)
-		{
-			static_assert(std::is_base_of<Memset<T>, T>::value, "Memset<T> must only clear the memory of a type of which it is a base class");
-
-			// GCC 8+ warns that
-			// "‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘T’;
-			//  use assignment or value-initialization instead [-Werror=class-memaccess]"
-			// This is benign iff it happens before any of the base or member constructrs are called.
-			#if defined(__GNUC__) && (__GNUC__ >= 8)
-			#pragma GCC diagnostic push
-			#pragma GCC diagnostic ignored "-Wclass-memaccess"
-			#endif
-
-			memset(object, 0, sizeof(T));
-
-			#if defined(__GNUC__) && (__GNUC__ >= 8)
-			#pragma GCC diagnostic pop
-			#endif
-		}
-	};
-
 	// Traits-like helper class for checking if objects can be compared using memcmp().
 	// Useful for statically asserting if a cache key can implement operator==() with memcmp().
 	template<typename T>
diff --git a/src/Device/Memset.hpp b/src/Device/Memset.hpp
new file mode 100644
index 0000000..8c015fa
--- /dev/null
+++ b/src/Device/Memset.hpp
@@ -0,0 +1,52 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef sw_Memset_hpp
+#define sw_Memset_hpp
+
+#include <cstring>
+#include <type_traits>
+
+namespace sw
+{
+	// Helper class for clearing the memory of objects at construction.
+	// Useful as the first base class of cache keys which may contain padding
+	// bytes or bits otherwise left uninitialized.
+	template<class T>
+	struct Memset
+	{
+		Memset(T *object, int val)
+		{
+			static_assert(std::is_base_of<Memset<T>, T>::value, "Memset<T> must only clear the memory of a type of which it is a base class");
+
+			// GCC 8+ warns that
+			// "‘void* memset(void*, int, size_t)’ clearing an object of non-trivial type ‘T’;
+			//  use assignment or value-initialization instead [-Werror=class-memaccess]"
+			// This is benign iff it happens before any of the base or member constructrs are called.
+			#if defined(__GNUC__) && (__GNUC__ >= 8)
+			#pragma GCC diagnostic push
+			#pragma GCC diagnostic ignored "-Wclass-memaccess"
+			#endif
+
+			memset(object, 0, sizeof(T));
+
+			#if defined(__GNUC__) && (__GNUC__ >= 8)
+			#pragma GCC diagnostic pop
+			#endif
+		}
+	};
+
+}
+
+#endif   // sw_Memset_hpp
\ No newline at end of file
diff --git a/src/Device/PixelProcessor.hpp b/src/Device/PixelProcessor.hpp
index 460afa4..c076a54 100644
--- a/src/Device/PixelProcessor.hpp
+++ b/src/Device/PixelProcessor.hpp
@@ -17,6 +17,7 @@
 
 #include "Color.hpp"
 #include "Context.hpp"
+#include "Memset.hpp"
 #include "RoutineCache.hpp"
 
 namespace sw
diff --git a/src/Device/Primitive.hpp b/src/Device/Primitive.hpp
index ba4dc03..0d23ec7 100644
--- a/src/Device/Primitive.hpp
+++ b/src/Device/Primitive.hpp
@@ -15,13 +15,22 @@
 #ifndef sw_Primitive_hpp
 #define sw_Primitive_hpp
 
+#include "Memset.hpp"
 #include "Vertex.hpp"
 #include "Device/Config.hpp"
+#include "System/Build.hpp"
 
 namespace sw
 {
-	struct Triangle
+	struct Triangle MEMORY_SANITIZER_ONLY(: Memset<Triangle>)
 	{
+#if MEMORY_SANITIZER_ENABLED
+		// Memory sanitizer cannot 'see' writes from JIT'd code, and can raise
+		// false-positives when read. By clearing the struct in the constructor,
+		// we can avoid triggering these false-positives.
+		inline Triangle() : Memset<Triangle>(this, 0) {}
+#endif // MEMORY_SANITIZER_ENABLED
+
 		Vertex v0;
 		Vertex v1;
 		Vertex v2;
@@ -34,8 +43,15 @@
 		float4 C;
 	};
 
-	struct Primitive
+	struct Primitive MEMORY_SANITIZER_ONLY(: Memset<Primitive>)
 	{
+#if MEMORY_SANITIZER_ENABLED
+		// Memory sanitizer cannot 'see' writes from JIT'd code, and can raise
+		// false-positives when read. By clearing the struct in the constructor,
+		// we can avoid triggering these false-positives.
+		inline Primitive() : Memset<Primitive>(this, 0) {}
+#endif // MEMORY_SANITIZER_ENABLED
+
 		int yMin;
 		int yMax;
 
diff --git a/src/Device/SetupProcessor.hpp b/src/Device/SetupProcessor.hpp
index a84f818..8a3374c 100644
--- a/src/Device/SetupProcessor.hpp
+++ b/src/Device/SetupProcessor.hpp
@@ -17,6 +17,7 @@
 
 #include <Pipeline/SpirvShader.hpp>
 #include "Context.hpp"
+#include "Memset.hpp"
 #include "RoutineCache.hpp"
 #include "System/Types.hpp"
 
diff --git a/src/Device/VertexProcessor.hpp b/src/Device/VertexProcessor.hpp
index 9133cb6..66ba01d 100644
--- a/src/Device/VertexProcessor.hpp
+++ b/src/Device/VertexProcessor.hpp
@@ -15,8 +15,9 @@
 #ifndef sw_VertexProcessor_hpp
 #define sw_VertexProcessor_hpp
 
-#include "Matrix.hpp"
 #include "Context.hpp"
+#include "Matrix.hpp"
+#include "Memset.hpp"
 #include "RoutineCache.hpp"
 #include "Vertex.hpp"
 #include "Pipeline/SpirvShader.hpp"
diff --git a/src/SwiftShader/SwiftShader.vcxproj b/src/SwiftShader/SwiftShader.vcxproj
index 78b8925..f09f6e8 100644
--- a/src/SwiftShader/SwiftShader.vcxproj
+++ b/src/SwiftShader/SwiftShader.vcxproj
@@ -429,6 +429,7 @@
     <ClInclude Include="..\Renderer\Context.hpp" />

     <ClInclude Include="..\Renderer\LRUCache.hpp" />

     <ClInclude Include="..\Renderer\Matrix.hpp" />

+    <ClInclude Include="..\Renderer\Memset.hpp" />

     <ClInclude Include="..\Renderer\PixelProcessor.hpp" />

     <ClInclude Include="..\Renderer\Plane.hpp" />

     <ClInclude Include="..\Renderer\Point.hpp" />

diff --git a/src/SwiftShader/SwiftShader.vcxproj.filters b/src/SwiftShader/SwiftShader.vcxproj.filters
index 64569cd..9ea9ce5 100644
--- a/src/SwiftShader/SwiftShader.vcxproj.filters
+++ b/src/SwiftShader/SwiftShader.vcxproj.filters
@@ -229,6 +229,9 @@
     <ClInclude Include="..\Renderer\Matrix.hpp">

       <Filter>Header Files\Renderer</Filter>

     </ClInclude>

+    <ClInclude Include="..\Renderer\Memset.hpp">

+      <Filter>Header Files\Renderer</Filter>

+    </ClInclude>

     <ClInclude Include="..\Renderer\PixelProcessor.hpp">

       <Filter>Header Files\Renderer</Filter>

     </ClInclude>

diff --git a/src/System/BUILD.gn b/src/System/BUILD.gn
index 38256f7..74d21c8 100644
--- a/src/System/BUILD.gn
+++ b/src/System/BUILD.gn
@@ -16,6 +16,7 @@
 
 swiftshader_source_set("System") {
   sources = [
+    "Build.hpp",
     "CPUID.cpp",
     "CPUID.hpp",
     "Configurator.cpp",
diff --git a/src/System/Build.hpp b/src/System/Build.hpp
new file mode 100644
index 0000000..85dc018
--- /dev/null
+++ b/src/System/Build.hpp
@@ -0,0 +1,39 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef Build_hpp
+#define Build_hpp
+
+// Define MEMORY_SANITIZER_ENABLED to 1 if the project was build with the memory
+// sanitizer enabled (-fsanitize=memory).
+#if defined(__SANITIZE_MEMORY__)
+#define MEMORY_SANITIZER_ENABLED 1
+#else // defined(__SANITIZE_MEMORY__)
+#if defined(__clang__)
+#if __has_feature(memory_sanitizer)
+#define MEMORY_SANITIZER_ENABLED 1
+#endif // __has_feature(memory_sanitizer)
+#endif // defined(__clang__)
+#endif // defined(__SANITIZE_MEMORY__)
+
+// MEMORY_SANITIZER_ONLY(X) resolves to X if MEMORY_SANITIZER_ENABLED is defined
+// to a non-zero value, otherwise MEMORY_SANITIZER_ONLY() is stripped by the
+// preprocessor.
+#if MEMORY_SANITIZER_ENABLED
+#define MEMORY_SANITIZER_ONLY(x) x
+#else
+#define MEMORY_SANITIZER_ONLY(x)
+#endif // MEMORY_SANITIZER_ENABLED
+
+#endif // Build_hpp
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index dd4def0..6451683 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -236,6 +236,7 @@
     <ClInclude Include="..\Device\ETC_Decoder.hpp" />

     <ClInclude Include="..\Device\LRUCache.hpp" />

     <ClInclude Include="..\Device\Matrix.hpp" />

+    <ClInclude Include="..\Device\Memset.hpp" />

     <ClInclude Include="..\Device\PixelProcessor.hpp" />

     <ClInclude Include="..\Device\Plane.hpp" />

     <ClInclude Include="..\Device\Point.hpp" />

@@ -263,6 +264,7 @@
     <ClInclude Include="..\Pipeline\VertexPipeline.hpp" />

     <ClInclude Include="..\Pipeline\VertexProgram.hpp" />

     <ClInclude Include="..\Pipeline\VertexRoutine.hpp" />

+    <ClInclude Include="..\System\Build.hpp" />

     <ClInclude Include="..\System\Configurator.hpp" />

     <ClInclude Include="..\System\CPUID.hpp" />

     <ClInclude Include="..\System\Debug.hpp" />

diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index 68eea69..7e5cadc 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -395,6 +395,9 @@
     <ClInclude Include="..\Device\Plane.hpp">

       <Filter>Header Files\Device</Filter>

     </ClInclude>

+    <ClInclude Include="..\Device\Memset.hpp">

+      <Filter>Header Files\Device</Filter>

+    </ClInclude>

     <ClInclude Include="..\Device\PixelProcessor.hpp">

       <Filter>Header Files\Device</Filter>

     </ClInclude>

@@ -452,6 +455,9 @@
     <ClInclude Include="..\Pipeline\PixelProgram.hpp">

       <Filter>Header Files\Pipeline</Filter>

     </ClInclude>

+    <ClInclude Include="..\System\Build.hpp">

+      <Filter>Header Files\System</Filter>

+    </ClInclude>

     <ClInclude Include="..\Pipeline\ComputeProgram.hpp">

       <Filter>Header Files\Pipeline</Filter>

     </ClInclude>