From c63a5afe710c539c2cfea139b5cb73061164fdc8 Mon Sep 17 00:00:00 2001
From: thorstenhater <24411438+thorstenhater@users.noreply.github.com>
Date: Mon, 10 May 2021 12:09:39 +0200
Subject: [PATCH] Add Clang's Leak, Thread, Memory, and Address Sanitizers.
 (#1501)

* Add a GH workflow to build and run Arbor tests and examples with Clang sanitizers.
* Fix some uninitialized struct members; missing `override` qualifiers.
---
 .github/workflows/sanitize.yml | 129 +++++++++++++++++++++++++++++++++
 modcc/printer/cexpr_emit.hpp   |   4 +-
 test/unit/test_simulation.cpp  |   4 +-
 3 files changed, 133 insertions(+), 4 deletions(-)
 create mode 100644 .github/workflows/sanitize.yml

diff --git a/.github/workflows/sanitize.yml b/.github/workflows/sanitize.yml
new file mode 100644
index 00000000..1c36ae74
--- /dev/null
+++ b/.github/workflows/sanitize.yml
@@ -0,0 +1,129 @@
+name: Sanitize
+
+on:
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  build:
+    name: "Sanitize"
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        name:      ["Linux Clang -fsanitize ${{ matrix.sanitizer }}"]
+        os:        ["ubuntu-20.04"]
+        cc:        ["clang-10"]
+        cxx:       ["clang++-10"]
+        py:        ["3.9"]
+        cmake:     ["3.19.x"]
+        mpi:       ["ON"]
+        simd:      ["ON", "OFF"]
+        sanitizer: ["address", "leak", "undefined", "memory", "thread"]
+    env:
+        CC:         ${{ matrix.cc }}
+        CXX:        ${{ matrix.cxx }}
+        # We set PYTHONPATH instead of installing arbor to avoid distribution/OS specific behaviour.
+        PYTHONPATH: ${{ github.workspace }}/build/python
+    steps:
+      - name: Set up cmake
+        uses: jwlawson/actions-setup-cmake@v1.7
+        with:
+          cmake-version: ${{ matrix.cmake }}
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.py }}
+      - name: OpenMPI cache
+        uses: actions/cache@v2
+        id:   cache-ompi
+        with:
+          path: ~/openmpi-4.0.2
+          key:  ${{ matrix.os }}-openmpi-4.0.2-${{ matrix.cxx }}
+      - name: Build OpenMPI
+        if: ${{ steps.cache-ompi.outputs.cache-hit != 'true' }}
+        run: |
+           echo cache-hit='${{ steps.cache-ompi.outputs.cache-hit }}'
+           cd ~
+           wget https://download.open-mpi.org/release/open-mpi/v4.0/openmpi-4.0.2.tar.gz
+           tar -xvf ./openmpi-4.0.2.tar.gz
+           cd openmpi-4.0.2
+           ./configure --disable-mpi-fortran
+           make -j4
+      - name: Install OpenMPI
+        run: |
+           echo "Going to install ompi"
+           cd ~
+           cd openmpi-4.0.2
+           sudo make install
+           cd -
+      - name: Update shared library cache
+        if: ${{ startsWith(matrix.os, 'ubuntu') }}
+        run: sudo ldconfig
+      - name: Install Python packages
+        run:  pip install numpy sphinx svgwrite sphinx-rtd-theme mpi4py pandas seaborn
+      - name: Clone w/ submodules
+        uses: actions/checkout@v2
+        with:
+          submodules: recursive
+      - name: Check config
+        run: |
+          $CC --version
+          $CXX --version
+          python --version
+          mpic++ --show
+          mpicc --show
+          echo $PYTHONPATH
+      - name: Build arbor
+        run: |
+          mkdir build
+          cd build
+          cmake .. -DCMAKE_BUILD_TYPE=debug -DCMAKE_CXX_FLAGS="-fsanitize=${{ matrix.sanitizer }} -fno-omit-frame-pointer" -DCMAKE_C_FLAGS="-fsanitize=${{ matrix.sanitizer }} -fno-omit-frame-pointer" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=${{ matrix.sanitizer }}" -DCMAKE_MODULE/_LINKER_FLAGS="-fsanitize=${{ matrix.sanitizer }}" -DCMAKE_CXX_COMPILER=$CXX -DCMAKE_C_COMPILER=$CC -DARB_WITH_PYTHON=ON -DARB_VECTORIZE=${{ matrix.simd }} -DPython3_EXECUTABLE=`which python` -DARB_WITH_MPI=${{ matrix.mpi }} -DARB_USE_BUNDLED_LIBS=ON
+          make -j4 tests examples pyarb html
+          cd -
+      - name: Run unit tests
+        run: |
+          build/bin/unit
+          build/bin/unit-modcc
+      - if:   ${{ matrix.mpi == 'ON' }}
+        name: Run MPI tests
+        run:  mpirun -n 4 -oversubscribe build/bin/unit-mpi
+      - if:   ${{ matrix.mpi == 'OFF' }}
+        name: Run examples
+        run: |
+            build/bin/bench
+            build/bin/brunel
+            build/bin/dryrun
+            build/bin/gap_junctions
+            build/bin/generators
+            build/bin/lfp
+            build/bin/probe-demo v
+            build/bin/ring
+            build/bin/single-cell
+      - if:   ${{ matrix.mpi == 'ON' }}
+        name: Run examples with MPI
+        run: |
+            mpirun -n 4 -oversubscribe build/bin/bench
+            mpirun -n 4 -oversubscribe build/bin/brunel
+            mpirun -n 4 -oversubscribe build/bin/dryrun
+            mpirun -n 4 -oversubscribe build/bin/gap_junctions
+            mpirun -n 4 -oversubscribe build/bin/generators
+            mpirun -n 4 -oversubscribe build/bin/lfp
+            mpirun -n 4 -oversubscribe build/bin/probe-demo v
+            mpirun -n 4 -oversubscribe build/bin/ring
+            mpirun -n 4 -oversubscribe build/bin/single-cell
+      - name: Run python tests
+        run: python python/test/unit/runner.py
+      - if:   ${{ matrix.mpi == 'ON' }}
+        name: Run python+MPI tests
+        run:  mpirun -n 4 -oversubscribe python python/test/unit_distributed/runner.py
+      - name: Run Python examples
+        run: |
+            python python/example/network_ring.py
+            python python/example/single_cell_model.py
+            python python/example/single_cell_recipe.py
+            python python/example/single_cell_stdp.py
+            python python/example/brunel.py -n 400 -m 100 -e 20 -p 0.1 -w 1.2 -d 1 -g 0.5 -l 5 -t 100 -s 1 -G 50 -S 123
+            python python/example/single_cell_swc.py python/example/single_cell_detailed.swc
+            python python/example/single_cell_detailed.py python/example/single_cell_detailed.swc
+            python python/example/single_cell_detailed_recipe.py python/example/single_cell_detailed.swc
diff --git a/modcc/printer/cexpr_emit.hpp b/modcc/printer/cexpr_emit.hpp
index f17cbf56..9a2c3dbc 100644
--- a/modcc/printer/cexpr_emit.hpp
+++ b/modcc/printer/cexpr_emit.hpp
@@ -60,8 +60,8 @@ public:
 
 protected:
     static std::unordered_set<std::string> mask_names_;
-    bool processing_true_;
-    bool is_indirect_;
+    bool processing_true_ = false;
+    bool is_indirect_ = false;
     std::string current_mask_, current_mask_bar_, input_mask_;
     std::unordered_set<std::string> scalars_;
     Visitor* fallback_;
diff --git a/test/unit/test_simulation.cpp b/test/unit/test_simulation.cpp
index 88d39b72..04c41ab4 100644
--- a/test/unit/test_simulation.cpp
+++ b/test/unit/test_simulation.cpp
@@ -92,7 +92,7 @@ struct lif_chain: public recipe {
         return lif;
     }
 
-    std::vector<cell_connection> connections_on(cell_gid_type target) const {
+    std::vector<cell_connection> connections_on(cell_gid_type target) const override {
         if (target) {
             return {cell_connection({target-1, 0}, 0, weight_, delay_)};
         }
@@ -101,7 +101,7 @@ struct lif_chain: public recipe {
         }
     }
 
-    std::vector<event_generator> event_generators(cell_gid_type target) const {
+    std::vector<event_generator> event_generators(cell_gid_type target) const override {
         if (target) {
             return {};
         }
-- 
GitLab