From 39a1c32a249bdb52c9ff847b10636aeb0394b890 Mon Sep 17 00:00:00 2001 From: Dave Amiana Date: Sun, 12 Jul 2026 23:35:23 +0800 Subject: [PATCH 1/3] adding semgrep rules and conf for scanning memory vulnerability and common anti-patterns --- .semgrep/.semgrepignore | 6 +++ .semgrep/rules/correctness.yml | 74 ++++++++++++++++++++++++++++++++ .semgrep/rules/memory-safety.yml | 54 +++++++++++++++++++++++ .semgrep/rules/security.yml | 62 ++++++++++++++++++++++++++ 4 files changed, 196 insertions(+) create mode 100644 .semgrep/.semgrepignore create mode 100644 .semgrep/rules/correctness.yml create mode 100644 .semgrep/rules/memory-safety.yml create mode 100644 .semgrep/rules/security.yml diff --git a/.semgrep/.semgrepignore b/.semgrep/.semgrepignore new file mode 100644 index 0000000..9e034d0 --- /dev/null +++ b/.semgrep/.semgrepignore @@ -0,0 +1,6 @@ +build/ +lib/ +docs_sphinx/_build/ +docs_doxy/ +.git/ +.vscode/ diff --git a/.semgrep/rules/correctness.yml b/.semgrep/rules/correctness.yml new file mode 100644 index 0000000..77cb895 --- /dev/null +++ b/.semgrep/rules/correctness.yml @@ -0,0 +1,74 @@ +rules: + - id: cpp-double-assignment + patterns: + - pattern: | + $VAR = $VAL1; + ... + $VAR = $VAL2; + - pattern-not: | + $VAR = $VAL1; + ... + $VAR = $VAL1; + message: | + Consecutive assignments to '$VAR' detected. The second assignment + overwrites the first, which is almost certainly a bug. Review the + logic to determine if one of the assignments should be removed or + if a different variable was intended. + languages: [cpp] + severity: ERROR + metadata: + category: correctness + cwe: "CWE-563: Assignment to Variable without Use" + confidence: HIGH + + - id: cpp-wrong-branch-condition + patterns: + - pattern: | + while ($NODE->left != $NIL) + $NODE = $NODE->right; + - pattern-not: | + while ($NODE->right != $NIL) + $NODE = $NODE->right; + message: | + Loop condition checks '$NODE->left' but the loop body advances + '$NODE->right'. This is likely a bug — the condition should + probably check '$NODE->right' instead. + languages: [cpp] + severity: ERROR + metadata: + category: correctness + cwe: "CWE-670: Always-Incorrect Control Flow Implementation" + confidence: HIGH + + - id: cpp-constructor-self-assign + pattern: | + $PTR = this; + message: | + Assigning 'this' to a raw pointer inside a constructor body. If + this pointer is later overwritten, the self-assignment is dead code + and likely indicates a logic error. Consider using the member + initializer list instead. + languages: [cpp] + severity: ERROR + metadata: + category: correctness + cwe: "CWE-563: Assignment to Variable without Use" + confidence: MEDIUM + + - id: cpp-nil-parent-set-nullptr + patterns: + - pattern: | + $NIL->parent = nullptr; + - metavariable-comparison: + metavariable: $NIL + comparison: $NIL == "NIL" + message: | + Setting NIL->parent to nullptr may break invariants if other code + checks 'parent == NIL'. This can cause null pointer dereferences + when traversing parent pointers. + languages: [cpp] + severity: ERROR + metadata: + category: correctness + cwe: "CWE-476: NULL Pointer Dereference" + confidence: MEDIUM diff --git a/.semgrep/rules/memory-safety.yml b/.semgrep/rules/memory-safety.yml new file mode 100644 index 0000000..737bcac --- /dev/null +++ b/.semgrep/rules/memory-safety.yml @@ -0,0 +1,54 @@ +rules: + - id: cpp-raw-new-without-raii + patterns: + - pattern: | + $TYPE * $VAR = new $T(...); + - pattern-not-inside: | + std::make_unique<...>(...) + - pattern-not-inside: | + std::make_shared<...>(...) + message: | + Raw 'new' without a RAII wrapper (std::unique_ptr or + std::shared_ptr). Raw owning pointers are error-prone and can + cause memory leaks. Prefer std::make_unique or std::make_shared. + languages: [cpp] + severity: WARNING + metadata: + category: memory-safety + cwe: "CWE-401: Memory Leak" + confidence: MEDIUM + references: + - https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r3-prefer-smart-pointers-to-raw-pointers + + - id: cpp-deref-after-delete + patterns: + - pattern: | + delete $PTR; + ... + ... $PTR ...; + - pattern: | + delete[] $PTR; + ... + ... $PTR ...; + message: | + Use of '$PTR' after delete. Accessing a pointer after it has been + freed leads to undefined behavior (use-after-free). + languages: [cpp] + severity: ERROR + metadata: + category: memory-safety + cwe: "CWE-416: Use After Free" + confidence: HIGH + + - id: cpp-return-local-address + pattern: return &$LOCAL; + message: | + Returning address of local variable '$LOCAL'. The pointer becomes + dangling as soon as the function returns, leading to undefined + behavior. + languages: [cpp] + severity: ERROR + metadata: + category: memory-safety + cwe: "CWE-562: Return of Stack Variable Address" + confidence: HIGH diff --git a/.semgrep/rules/security.yml b/.semgrep/rules/security.yml new file mode 100644 index 0000000..be7340f --- /dev/null +++ b/.semgrep/rules/security.yml @@ -0,0 +1,62 @@ +rules: + - id: cpp-exit-in-catch + pattern: | + catch (...) { + ... + exit(...); + } + message: | + Calling exit() inside a catch block terminates the process without + unwinding the stack or cleaning up resources. Prefer throwing an + exception or returning an error code. + languages: [cpp] + severity: WARNING + metadata: + category: security + cwe: "CWE-754: Improper Check for Unusual or Exceptional Conditions" + confidence: HIGH + + - id: cpp-exit-in-catch-specific + pattern: | + catch ($TYPE $E) { + ... + exit(...); + } + message: | + Calling exit() inside a catch block terminates the process without + unwinding the stack or cleaning up resources. Prefer throwing an + exception or returning an error code. + languages: [cpp] + severity: WARNING + metadata: + category: security + cwe: "CWE-754: Improper Check for Unusual or Exceptional Conditions" + confidence: HIGH + + - id: cpp-c-style-cast + pattern: ($TYPE) $EXPR + message: | + C-style cast detected. Prefer C++ casts (static_cast, const_cast, + reinterpret_cast) for type safety and better error diagnostics. + languages: [cpp] + severity: WARNING + metadata: + category: security + cwe: "CWE-704: Incorrect Type Conversion" + confidence: HIGH + references: + - https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es48-avoid-casts + + - id: cpp-exception-by-value + pattern: catch ($TYPE $E) { ... } + message: | + Catching exception by value may slice derived exceptions. Catch + by reference instead: catch (const $TYPE& $E). + languages: [cpp] + severity: WARNING + metadata: + category: security + cwe: "CWE-398: Code Quality" + confidence: MEDIUM + references: + - https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Re-catching From fb8cddeccf164752a5be04eb32f8c5270b95e4bd Mon Sep 17 00:00:00 2001 From: Dave Amiana Date: Sun, 12 Jul 2026 23:37:54 +0800 Subject: [PATCH 2/3] adding semgrep build routine on ci workflows and fixes on docs build conf --- .github/workflows/cpp.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml index 858e34c..4799d61 100644 --- a/.github/workflows/cpp.yml +++ b/.github/workflows/cpp.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: git run: git --version - name: configure @@ -20,6 +20,7 @@ jobs: pip3 install breathe pip3 install pydata-sphinx-theme pip3 install sphinx-sitemap + pip3 install semgrep - name: gtest run: | sudo apt-get install libgtest-dev @@ -43,12 +44,12 @@ jobs: run: | cd ${{github.workspace}}/build ctest --output-on-failure - - name: checkout repo - uses: actions/checkout@1.0.0 + - name: semgrep + run: | + semgrep scan --config .semgrep/rules/ src/ include/ test/ - name: build docs run: | cd docs_sphinx - doxygen Doxyfile.in make html cd _build/html touch .nojekyll From cbf5cbe6428e9153a9066fcd05c219f99923aaf6 Mon Sep 17 00:00:00 2001 From: Dave Amiana Date: Sun, 12 Jul 2026 23:38:15 +0800 Subject: [PATCH 3/3] fixing docs issue to render apidoc --- docs_sphinx/api/cpp_doxygen_sphinx.rst | 3 ++- docs_sphinx/api/index.rst | 1 - docs_sphinx/conf.py | 2 -- docs_sphinx/index.rst | 2 ++ 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs_sphinx/api/cpp_doxygen_sphinx.rst b/docs_sphinx/api/cpp_doxygen_sphinx.rst index e7b1310..d3ef9f6 100644 --- a/docs_sphinx/api/cpp_doxygen_sphinx.rst +++ b/docs_sphinx/api/cpp_doxygen_sphinx.rst @@ -2,5 +2,6 @@ TreeSet API ============= + .. doxygenfile:: TreeSet.hpp - :project: C++ Sphinx Doxygen Breathe + :project: C++ Sphinx Doxygen Breathe diff --git a/docs_sphinx/api/index.rst b/docs_sphinx/api/index.rst index 154e5d7..6cb5599 100644 --- a/docs_sphinx/api/index.rst +++ b/docs_sphinx/api/index.rst @@ -4,7 +4,6 @@ API === .. toctree:: - :maxdepth: 2 :glob: diff --git a/docs_sphinx/conf.py b/docs_sphinx/conf.py index b0f46a2..16b64ba 100644 --- a/docs_sphinx/conf.py +++ b/docs_sphinx/conf.py @@ -14,9 +14,7 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) -from sphinx.builders.html import StandaloneHTMLBuilder import subprocess -import os # Doxygen subprocess.call('doxygen Doxyfile.in', shell=True) diff --git a/docs_sphinx/index.rst b/docs_sphinx/index.rst index 2a0f256..a8a2478 100644 --- a/docs_sphinx/index.rst +++ b/docs_sphinx/index.rst @@ -10,6 +10,8 @@ Welcome to TreeSet's documentation! :maxdepth: 2 :caption: Contents: + api/index + .. image:: ../img/TreeSetLogo.png :alt: logo :align: center