Reduce clr startup noise when using Clang sanitizers
authorSteve Harter <sharter@microsoft.com>
Wed, 16 Dec 2015 20:27:26 +0000 (14:27 -0600)
committerSteve Harter <sharter@microsoft.com>
Thu, 21 Jan 2016 21:23:16 +0000 (15:23 -0600)
CMakeLists.txt
enablesanitizers.sh
sanitizerblacklist.txt [new file with mode: 0644]
src/gc/handletable.cpp
src/gc/handletablecore.cpp
src/inc/clrhost.h
src/vm/vars.hpp

index c7b53ef..64a6eb9 100644 (file)
@@ -321,7 +321,7 @@ if (CLR_CMAKE_PLATFORM_UNIX)
     string(FIND "$ENV{DEBUG_SANITIZERS}" "asan" __ASAN_POS)
     string(FIND "$ENV{DEBUG_SANITIZERS}" "ubsan" __UBSAN_POS)
     if ((${__ASAN_POS} GREATER -1) OR (${__UBSAN_POS} GREATER -1))
-      set(CLR_SANITIZE_CXX_FLAGS "${CLR_SANITIZE_CXX_FLAGS} -fsanitize=")
+      set(CLR_SANITIZE_CXX_FLAGS "${CLR_SANITIZE_CXX_FLAGS} -fsanitize-blacklist=${CMAKE_CURRENT_SOURCE_DIR}/sanitizerblacklist.txt -fsanitize=")
       set(CLR_SANITIZE_LINK_FLAGS "${CLR_SANITIZE_LINK_FLAGS} -fsanitize=")
       if (${__ASAN_POS} GREATER -1) 
         set(CLR_SANITIZE_CXX_FLAGS "${CLR_SANITIZE_CXX_FLAGS}address,")
index 0afec5d..70555aa 100755 (executable)
@@ -10,15 +10,17 @@ if [ $# -eq 0 ]; then
         echo " cd $(dirname $0);. enablesanitizers.sh [options]; cd -"
     fi
     echo "Usage: [asan] [ubsan] [lsan] [all] [off] [clangx.y]"
-    echo "asan: optional argument to enable Address Sanitizer."
-    echo "ubsan: optional argument to enable Undefined Behavior Sanitizer."
-    echo "lsan - optional argument to enable memory Leak Sanitizer."
-    echo "all - optional argument to enable asan, ubsan and lsan."
-    echo "off - optional argument to turn off all sanitizers."
-    echo "clangx.y - optional argument to specify clang version x.y. which is used to resolve stack traces."
+    echo " asan: optional argument to enable Address Sanitizer."
+    echo " ubsan: optional argument to enable Undefined Behavior Sanitizer."
+    echo " lsan - optional argument to enable memory Leak Sanitizer."
+    echo " all - optional argument to enable asan, ubsan and lsan."
+    echo " off - optional argument to turn off all sanitizers."
+    echo " clangx.y - optional argument to specify clang version x.y. which is used to resolve stack traces. Default is 3.6"
 else
+    # default to clang 3.6 instead of 3.5 because it supports print_stacktrace (otherwise only one stack frame)
     __ClangMajorVersion=3
-    __ClangMinorVersion=5
+    __ClangMinorVersion=6
+
     __EnableASan=0
     __EnableUBSan=0
     __EnableLSan=0
@@ -69,7 +71,10 @@ else
         unset DEBUG_SANITIZERS
         echo "Setting DEBUG_SANITIZERS="
     else
-        ASAN_OPTIONS="symbolize=1"
+        # for now, specify alloc_dealloc_mismatch=0 as there are too many error reports that are not an issue
+        ASAN_OPTIONS="symbolize=1 alloc_dealloc_mismatch=0"
+        # when Clang 3.8 available, add: suppressions=$(readlink -f sanitizersuppressions.txt)
+        UBSAN_OPTIONS="print_stacktrace=1"
 
         if [ $__EnableASan == 1 ]; then
             __Options="$__Options asan"
@@ -91,10 +96,15 @@ else
         export ASAN_OPTIONS
         echo "Setting ASAN_OPTIONS=$ASAN_OPTIONS"
 
+        UBSAN_OPTIONS="\"$UBSAN_OPTIONS\""
+        export UBSAN_OPTIONS
+        echo "Setting UBSAN_OPTIONS=$UBSAN_OPTIONS"
+
         # used by ASan at run-time
         ASAN_SYMBOLIZER_PATH="/usr/bin/llvm-symbolizer-$__ClangMajorVersion.$__ClangMinorVersion"
         export ASAN_SYMBOLIZER_PATH
         echo "Setting ASAN_SYMBOLIZER_PATH=$ASAN_SYMBOLIZER_PATH"
+        echo "Done. You can now run: build.sh Debug clang$__ClangMajorVersion.$__ClangMinorVersion"
     fi
 
     unset __ClangMajorVersion
diff --git a/sanitizerblacklist.txt b/sanitizerblacklist.txt
new file mode 100644 (file)
index 0000000..ec33139
--- /dev/null
@@ -0,0 +1,14 @@
+# This file has exclusions to the Clang address sanitizer to suppress error reports
+# When Clang 3.8 is available, convert these to suppression list instead as that is preferred for internal code
+
+# CMiniMdBase::UsesAllocatedMemory - suppress stack-buffer-underflow (code backs up pointer by -1 to check allocation ownership)
+fun:_ZN11CMiniMdBase19UsesAllocatedMemoryEP11CMiniColDef
+
+# JIT_InitPInvokeFrame - suppress unknown sanitizer issue causing SEGV on unknown address 0x000000000000
+# 0 0x4e8a0c in __ubsan::checkDynamicType(void*, void*, unsigned long)
+# 1 0x4e807f in HandleDynamicTypeCacheMiss(__ubsan::DynamicTypeCacheMissData*, unsigned long, unsigned long, __ubsan::ReportOptions)
+# 2 0x4e8051 in __ubsan_handle_dynamic_type_cache_miss
+# 3 0x7f02ce676cd8 in JIT_InitPInvokeFrame(InlinedCallFrame*, void*) /home/steveharter/git/dotnet_coreclr/src/vm/jithelpers.cpp:6491:9
+# 4 0x7f0252bbceb2  (<unknown module>)
+fun:_Z20JIT_InitPInvokeFrameP16InlinedCallFramePv
+
index 7f855bb..7ded783 100644 (file)
@@ -391,11 +391,11 @@ void ValidateFetchObjrefForHandle(OBJECTREF objref, ADIndex appDomainIndex)
     _ASSERTE(!pDomain->NoAccessToHandleTable());
 
 #if CHECK_APP_DOMAIN_LEAKS
-    if (g_pConfig->AppDomainLeaks())
+       if (g_pConfig->AppDomainLeaks() && objref != NULL)
     {
         if (appDomainIndex.m_dwIndex)
             objref->TryAssignAppDomain(pDomain);
-        else if (objref != 0)
+        else
             objref->TrySetAppDomainAgile();
     }
 #endif
@@ -421,11 +421,11 @@ void ValidateAssignObjrefForHandle(OBJECTREF objref, ADIndex appDomainIndex)
     _ASSERTE(!pDomain->NoAccessToHandleTable());
 
 #if CHECK_APP_DOMAIN_LEAKS
-    if (g_pConfig->AppDomainLeaks())
+    if (g_pConfig->AppDomainLeaks() && objref != NULL)
     {
         if (appDomainIndex.m_dwIndex)
             objref->TryAssignAppDomain(pDomain);
-        else if (objref != 0)
+        else
             objref->TrySetAppDomainAgile();
     }
 #endif
index d302087..10c6649 100644 (file)
@@ -1984,15 +1984,17 @@ uint32_t BlockAllocHandlesInitial(TableSegment *pSegment, uint32_t uType, uint32
         uint32_t uAlloc = uRemain;
 
         // compute the default mask based on that count
-        uint32_t dwNewMask = (MASK_EMPTY << uAlloc);
-
+        uint32_t dwNewMask;
         // are we allocating all of them?
         if (uAlloc >= HANDLE_HANDLES_PER_MASK)
         {
-            // shift above has unpredictable results in this case
-            dwNewMask = MASK_FULL;
+            dwNewMask = MASK_FULL; // avoid unpredictable shift
             uAlloc = HANDLE_HANDLES_PER_MASK;
         }
+        else
+        {
+            dwNewMask = (MASK_EMPTY << uAlloc);
+        }
 
         // set the free mask
         *pdwMask = dwNewMask;
index 8268c9a..3d1a8fa 100644 (file)
@@ -85,6 +85,8 @@ void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback);
 // Function pointer for fast TLS fetch - do not use directly
 typedef LPVOID (*POPTIMIZEDTLSGETTER)();
 
+typedef LPVOID* (*CLRFLSGETBLOCK)();
+
 extern POPTIMIZEDTLSGETTER __ClrFlsGetBlock;
 
 #ifndef CLR_STANDALONE_BINDER
@@ -98,8 +100,9 @@ inline void ClrFlsIncrementValue(DWORD slot, int increment)
     STATIC_CONTRACT_SO_TOLERANT;
 
     _ASSERTE(increment != 0);
-
-    void **block = (void **) (*__ClrFlsGetBlock)();
+    
+    CLRFLSGETBLOCK clrFlsGetBlockFn = (CLRFLSGETBLOCK)__ClrFlsGetBlock;
+    void **block = (*clrFlsGetBlockFn)();
     size_t value;
 
     if (block != NULL)
@@ -134,7 +137,8 @@ inline void * ClrFlsGetValue (DWORD slot)
     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
     STATIC_CONTRACT_SO_TOLERANT;
 
-    void **block = (void **) (*__ClrFlsGetBlock)();
+    CLRFLSGETBLOCK clrFlsGetBlockFn = (CLRFLSGETBLOCK)__ClrFlsGetBlock;
+    void **block = (*clrFlsGetBlockFn)();
     if (block != NULL)
     {
         return block[slot];
@@ -159,7 +163,8 @@ inline BOOL ClrFlsCheckValue(DWORD slot, void ** pValue)
 #ifdef _DEBUG
     *pValue = ULongToPtr(0xcccccccc);
 #endif //_DEBUG 
-    void **block = (void **) (*__ClrFlsGetBlock)();
+    CLRFLSGETBLOCK clrFlsGetBlockFn = (CLRFLSGETBLOCK)__ClrFlsGetBlock;
+    void **block = (*clrFlsGetBlockFn)();
     if (block != NULL)
     {
         *pValue = block[slot];
@@ -181,7 +186,8 @@ inline void ClrFlsSetValue(DWORD slot, void *pData)
     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
     STATIC_CONTRACT_SO_TOLERANT;
 
-    void **block = (void **) (*__ClrFlsGetBlock)();
+    CLRFLSGETBLOCK clrFlsGetBlockFn = (CLRFLSGETBLOCK)__ClrFlsGetBlock;
+    void **block = (*clrFlsGetBlockFn)();
     if (block != NULL)
     {
         block[slot] = pData;
index cfb4a93..5286930 100644 (file)
@@ -341,8 +341,9 @@ class REF : public OBJECTREF
 
 };
 
-#define VALIDATEOBJECTREF(objref) ((objref).Validate())
-#define VALIDATEOBJECT(obj) obj->Validate()
+// the while (0) syntax below is to force a trailing semicolon on users of the macro
+#define VALIDATEOBJECTREF(objref) do {if ((objref) != NULL) (objref).Validate();} while (0)
+#define VALIDATEOBJECT(obj) do {if ((obj) != NULL) (obj)->Validate();} while (0)
 
 #define ObjectToOBJECTREF(obj)     (OBJECTREF(obj))
 #define OBJECTREFToObject(objref)  ((objref).operator-> ())