Browse Source

Merge pull request #40994 from qarmin/sanitization32

[3.2] Added Linux sanitizer with xvfb to github workspace
Rémi Verschelde 4 years ago
parent
commit
0c3e0ab194

+ 80 - 0
.github/workflows/linux_builds.yml

@@ -115,3 +115,83 @@ jobs:
           SCONS_CACHE: ${{github.workspace}}/.scons_cache/
           SCONS_CACHE: ${{github.workspace}}/.scons_cache/
         run: |
         run: |
           scons -j2 verbose=yes warnings=all werror=yes platform=x11 target=release tools=no module_mono_enabled=yes mono_glue=no
           scons -j2 verbose=yes warnings=all werror=yes platform=x11 target=release tools=no module_mono_enabled=yes mono_glue=no
+
+  linux-sanitizer:
+    runs-on: "ubuntu-20.04"
+    name: Editor and exported project  with sanitizers(target=debug/release, tools=yes/no, debug_symbols=yes/full, use_ubsan=yes, use_asan=yes)
+
+    steps:
+      - uses: actions/checkout@v2
+
+      # Azure repositories are not reliable, we need to prevent azure giving us packages.
+      - name: Make apt sources.list use the default Ubuntu repositories
+        run: |
+          sudo cp -f misc/ci/sources.list /etc/apt/sources.list
+          sudo apt-get update
+
+      # Install all packages (except scons)
+      - name: Configure dependencies
+        run: |
+          sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \
+            libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm \
+            xvfb wget2 unzip
+
+      # Upload cache on completion and check it out now
+      - name: Load .scons_cache directory
+        id: linux-editor-cache
+        uses: actions/cache@v2
+        with:
+          path: ${{github.workspace}}/.scons_cache/
+          key: ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+          restore-keys: |
+            ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}-${{github.sha}}
+            ${{github.job}}-${{env.GODOT_BASE_BRANCH}}-${{github.ref}}
+            ${{github.job}}-${{env.GODOT_BASE_BRANCH}}
+
+      # Use python 3.x release (works cross platform; best to keep self contained in it's own step)
+      - name: Set up Python 3.x
+        uses: actions/setup-python@v2
+        with:
+          # Semantic version range syntax or exact version of a Python version
+          python-version: '3.x'
+          # Optional - x64 or x86 architecture, defaults to x64
+          architecture: 'x64'
+
+      # Setup scons, print python version and scons version info, so if anything is broken it won't run the build.
+      - name: Configuring Python packages
+        run: |
+          python -c "import sys; print(sys.version)"
+          python -m pip install scons
+          python --version
+          scons --version
+
+      # We should always be explicit with our flags usage here since it's gonna be sure to always set those flags
+      - name: Compilation
+        env:
+          SCONS_CACHE: ${{github.workspace}}/.scons_cache/
+        run: |
+          scons -j2 verbose=yes warnings=all werror=yes platform=x11 tools=yes target=debug use_ubsan=yes use_asan=yes
+          scons -j2 verbose=yes warnings=all werror=yes platform=x11 tools=no target=release debug_symbols=full use_ubsan=yes use_asan=yes
+
+      # Download and test project to check leaks and invalid memory usage
+      - name: Importing and running project project
+        run: |
+          wget2 https://github.com/qarmin/RegressionTestProject/archive/3.2.zip
+          unzip 3.2.zip
+          mv "RegressionTestProject-3.2" "test_project"
+          DRI_PRIME=0 timeout 25s xvfb-run bin/godot.x11.tools.64s -e --path test_project 2>&1 | tee sanitizers_log.txt || true
+          misc/scripts/check_ci_log.py sanitizers_log.txt
+          DRI_PRIME=0 xvfb-run bin/godot.x11.tools.64s 20 --video-driver GLES3 --path test_project 2>&1 | tee sanitizers_log.txt || true
+          misc/scripts/check_ci_log.py sanitizers_log.txt
+
+      # Export project and run it to check for possible leaks and invalid memory usage
+      - name: Exporting and running project
+        run: |
+          mkdir exported_project
+          sed -i 's:PATH_TO_CHANGE:'`pwd`/bin/godot.x11.debug.64s':' test_project/export_presets.cfg
+          cd test_project
+          DRI_PRIME=0 xvfb-run ../bin/godot.x11.tools.64s --export-debug "Linux/X11" ../exported_project/test_project 2>&1 | tee sanitizers_log.txt || true
+          cd ..
+          misc/scripts/check_ci_log.py sanitizers_log.txt
+          DRI_PRIME=0 xvfb-run exported_project/test_project 20 2>&1 | tee sanitizers_log.txt || true
+          misc/scripts/check_ci_log.py sanitizers_log.txt

+ 3 - 0
editor/editor_resource_preview.cpp

@@ -168,6 +168,9 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
 		}
 		}
 		r_texture = generated;
 		r_texture = generated;
 
 
+		if (!EditorNode::get_singleton()->get_theme_base())
+			return;
+
 		int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size
 		int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_icon("Object", "EditorIcons")->get_width(); // Kind of a workaround to retrieve the default icon size
 		small_thumbnail_size *= EDSCALE;
 		small_thumbnail_size *= EDSCALE;
 
 

+ 51 - 0
misc/scripts/check_ci_log.py

@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+
+if len(sys.argv) < 2:
+    print("ERROR: You must run program with file name as argument.")
+    sys.exit(1)
+
+fname = sys.argv[1]
+
+fileread = open(fname.strip(), "r")
+file_contents = fileread.read()
+
+# If find "ERROR: AddressSanitizer:", then happens invalid read or write
+# This is critical bug, so we need to fix this as fast as possible
+
+if file_contents.find("ERROR: AddressSanitizer:") != -1:
+    print("FATAL ERROR: An incorrectly used memory was found.")
+    sys.exit(1)
+
+# There is also possible, that program crashed with or without backtrace.
+
+if (
+    file_contents.find("Program crashed with signal") != -1
+    or file_contents.find("Dumping the backtrace") != -1
+    or file_contents.find("Segmentation fault (core dumped)") != -1
+):
+    print("FATAL ERROR: Godot has been crashed.")
+    sys.exit(1)
+
+# Finding memory leaks in Godot is quite difficult, because we need to take into
+# account leaks also in external libraries. They are usually provided without
+# debugging symbols, so the leak report from it usually has only 2/3 lines,
+# so searching for 5 element - "#4 0x" - should correctly detect the vast
+# majority of memory leaks
+
+if file_contents.find("ERROR: LeakSanitizer:") != -1:
+    if file_contents.find("#4 0x") != -1:
+        print("ERROR: Memory leak was found")
+        sys.exit(1)
+
+# It may happen that Godot detects leaking nodes/resources and removes them, so
+# this possibility should also be handled as a potential error, even if
+# LeakSanitizer doesn't report anything
+
+if file_contents.find("ObjectDB instances leaked at exit") != -1:
+    print("ERROR: Memory leak was found")
+    sys.exit(1)
+
+sys.exit(0)

+ 12 - 8
platform/osx/detect.py

@@ -43,10 +43,11 @@ def configure(env):
     ## Build type
     ## Build type
 
 
     if env["target"] == "release":
     if env["target"] == "release":
-        if env["optimize"] == "speed":  # optimize for speed (default)
-            env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize", "-msse2"])
-        else:  # optimize for size
-            env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize", "-msse2"])
+        if env["debug_symbols"] != "full":
+            if env["optimize"] == "speed":  # optimize for speed (default)
+                env.Prepend(CCFLAGS=["-O3", "-fomit-frame-pointer", "-ftree-vectorize", "-msse2"])
+            else:  # optimize for size
+                env.Prepend(CCFLAGS=["-Os", "-ftree-vectorize", "-msse2"])
 
 
         if env["debug_symbols"] == "yes":
         if env["debug_symbols"] == "yes":
             env.Prepend(CCFLAGS=["-g1"])
             env.Prepend(CCFLAGS=["-g1"])
@@ -54,11 +55,14 @@ def configure(env):
             env.Prepend(CCFLAGS=["-g2"])
             env.Prepend(CCFLAGS=["-g2"])
 
 
     elif env["target"] == "release_debug":
     elif env["target"] == "release_debug":
-        if env["optimize"] == "speed":  # optimize for speed (default)
-            env.Prepend(CCFLAGS=["-O2"])
-        else:  # optimize for size
-            env.Prepend(CCFLAGS=["-Os"])
+        if env["debug_symbols"] != "full":
+            if env["optimize"] == "speed":  # optimize for speed (default)
+                env.Prepend(CCFLAGS=["-O2"])
+            else:  # optimize for size
+                env.Prepend(CCFLAGS=["-Os"])
+
         env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
         env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
+
         if env["debug_symbols"] == "yes":
         if env["debug_symbols"] == "yes":
             env.Prepend(CCFLAGS=["-g1"])
             env.Prepend(CCFLAGS=["-g1"])
         if env["debug_symbols"] == "full":
         if env["debug_symbols"] == "full":

+ 10 - 8
platform/windows/detect.py

@@ -177,19 +177,21 @@ def configure_msvc(env, manual_msvc_config):
     # Build type
     # Build type
 
 
     if env["target"] == "release":
     if env["target"] == "release":
-        if env["optimize"] == "speed":  # optimize for speed (default)
-            env.Append(CCFLAGS=["/O2"])
-        else:  # optimize for size
-            env.Append(CCFLAGS=["/O1"])
+        if env["debug_symbols"] != "full":
+            if env["optimize"] == "speed":  # optimize for speed (default)
+                env.Append(CCFLAGS=["/O2"])
+            else:  # optimize for size
+                env.Append(CCFLAGS=["/O1"])
         env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
         env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
         env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
         env.Append(LINKFLAGS=["/ENTRY:mainCRTStartup"])
         env.Append(LINKFLAGS=["/OPT:REF"])
         env.Append(LINKFLAGS=["/OPT:REF"])
 
 
     elif env["target"] == "release_debug":
     elif env["target"] == "release_debug":
-        if env["optimize"] == "speed":  # optimize for speed (default)
-            env.Append(CCFLAGS=["/O2"])
-        else:  # optimize for size
-            env.Append(CCFLAGS=["/O1"])
+        if env["debug_symbols"] != "full":
+            if env["optimize"] == "speed":  # optimize for speed (default)
+                env.Append(CCFLAGS=["/O2"])
+            else:  # optimize for size
+                env.Append(CCFLAGS=["/O1"])
         env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
         env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
         env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
         env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
         env.Append(LINKFLAGS=["/OPT:REF"])
         env.Append(LINKFLAGS=["/OPT:REF"])

+ 27 - 11
platform/x11/detect.py

@@ -85,10 +85,11 @@ def configure(env):
     ## Build type
     ## Build type
 
 
     if env["target"] == "release":
     if env["target"] == "release":
-        if env["optimize"] == "speed":  # optimize for speed (default)
-            env.Prepend(CCFLAGS=["-O3"])
-        else:  # optimize for size
-            env.Prepend(CCFLAGS=["-Os"])
+        if env["debug_symbols"] != "full":
+            if env["optimize"] == "speed":  # optimize for speed (default)
+                env.Prepend(CCFLAGS=["-O3"])
+            else:  # optimize for size
+                env.Prepend(CCFLAGS=["-Os"])
 
 
         if env["debug_symbols"] == "yes":
         if env["debug_symbols"] == "yes":
             env.Prepend(CCFLAGS=["-g1"])
             env.Prepend(CCFLAGS=["-g1"])
@@ -96,10 +97,12 @@ def configure(env):
             env.Prepend(CCFLAGS=["-g2"])
             env.Prepend(CCFLAGS=["-g2"])
 
 
     elif env["target"] == "release_debug":
     elif env["target"] == "release_debug":
-        if env["optimize"] == "speed":  # optimize for speed (default)
-            env.Prepend(CCFLAGS=["-O2"])
-        else:  # optimize for size
-            env.Prepend(CCFLAGS=["-Os"])
+        if env["debug_symbols"] != "full":
+            if env["optimize"] == "speed":  # optimize for speed (default)
+                env.Prepend(CCFLAGS=["-O2"])
+            else:  # optimize for size
+                env.Prepend(CCFLAGS=["-Os"])
+
         env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
         env.Prepend(CPPDEFINES=["DEBUG_ENABLED"])
 
 
         if env["debug_symbols"] == "yes":
         if env["debug_symbols"] == "yes":
@@ -146,11 +149,24 @@ def configure(env):
         env.extra_suffix += "s"
         env.extra_suffix += "s"
 
 
         if env["use_ubsan"]:
         if env["use_ubsan"]:
-            env.Append(CCFLAGS=["-fsanitize=undefined"])
-            env.Append(LINKFLAGS=["-fsanitize=undefined"])
+            env.Append(
+                CCFLAGS=[
+                    "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+                ]
+            )
+
+            if env["use_llvm"]:
+                env.Append(
+                    CCFLAGS=[
+                        "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change,implicit-signed-integer-truncation,implicit-unsigned-integer-truncation"
+                    ]
+                )
+            else:
+                env.Append(CCFLAGS=["-fsanitize=bounds-strict"])
+        env.Append(LINKFLAGS=["-fsanitize=undefined"])
 
 
         if env["use_asan"]:
         if env["use_asan"]:
-            env.Append(CCFLAGS=["-fsanitize=address"])
+            env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
             env.Append(LINKFLAGS=["-fsanitize=address"])
             env.Append(LINKFLAGS=["-fsanitize=address"])
 
 
         if env["use_lsan"]:
         if env["use_lsan"]: