Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/build-ghidra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ jobs:
# CI on any regression that reintroduces unfiltered deserialization.
run: gradle objectInputStreamAudit

- name: Audit C++ RAII protected files (Rec 31 #31-2)
# Forbid raw `new` allocations in decompile/cpp/address.cc,
# space.cc, rangeutil.cc. Already RAII-clean (zero raw new);
# this gate fails CI on any regression that reintroduces a
# raw owning pointer in the protected set. Set extends as
# later RAII stages (#31-3+) convert more files.
run: gradle cppRaiiAudit

- name: i18n lint (Docking)
# Localization PoC: fail the build if a hardcoded UI literal
# reappears in Ghidra/Framework/Docking outside the
Expand Down
2 changes: 1 addition & 1 deletion SprintPlanning.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ first implementation tier.

- [x] ~~**Rec 32 PR #32-2:** bump `-std=c++11` → `-std=c++14` in `decompile/cpp/Makefile`.~~ Shipped: [PR #310](https://github.com/CryptoJones/GayHydra/pull/310).
- [x] ~~**Rec 32 PR #32-3:** bump to `-std=c++20`.~~ Shipped: rolled in with [PR #314](https://github.com/CryptoJones/GayHydra/pull/314); same three sites as #32-2 (`buildNatives.gradle` Gcc/Clang blocks, `decompile/cpp/Makefile`, `decompile/cpp/fuzz/Makefile.fuzz`), flag-only change. Toolchain floor recorded in `docs/decompiler/CPP20_ADOPTION.md` (gcc ≥10, clang ≥12, MSVC 2019 16.10+/2022).
- [ ] **Rec 31 PR #31-2:** RAII Stage 1 — convert `address.cc`, `space.cc`, `range.cc` to `unique_ptr`. CI lint: no raw `new` in these files.
- [x] ~~**Rec 31 PR #31-2:** RAII Stage 1 — convert `address.cc`, `space.cc`, `range.cc` to `unique_ptr`. CI lint: no raw `new` in these files.~~ Shipped: the three foundation files were already raw-`new`-free in tree (only `new` mentions are in comments); the `gradle cppRaiiAudit` per-file gate was added to fail CI on any regression. Tree path uses `rangeutil.cc` (the file the audit named as `range.cc`).
- [ ] **Rec 31 PR #31-3 + Rec 32 PR #32-4:** RAII Stage 2 (`marshal.cc`, `xml.cc`) paired with `std::span` adoption in their parameter pairs. Joint review.

---
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ apply from: 'gradle/ignoreAudit.gradle'
// Raw ObjectInputStream enforcement gate. See docs/security/JAVA_DESERIALIZATION_AUDIT.md (Rec 19 #19-6).
apply from: 'gradle/objectInputStreamAudit.gradle'

// C++ RAII audit — protected-file gate. See docs/decompiler/CPP20_ADOPTION.md (Rec 31 #31-2).
apply from: 'gradle/cppRaiiAudit.gradle'


/***************************************************************************************
* Print current Java and Gradle version and make sure the correct version of gradle is being used
Expand Down
24 changes: 12 additions & 12 deletions docs/decompiler/RAII_MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,18 @@ can land at C++11 and C++20 later.

## Sequencing

| PR | Scope |
|---|---|
| #31-1 (this PR) | This plan |
| #31-2 | Stage 1 — `address.cc`, `space.cc`, `range.cc` |
| #31-3 | Stage 2 — `marshal.cc`, `xml.cc` |
| #31-4 | Stage 3 — `database.cc`, `comment.cc`, `cover.cc` |
| #31-5 | Stage 4 — `type.cc`, `userop.cc` |
| #31-6 | Stage 5 — pcode core |
| #31-7 | Stage 6 — analysis passes |
| #31-8 | Stage 7 — Sleigh runtime (parallel to #31-7) |
| #31-9 | Stage 8 — mop-up |
| #31-10 | CI lint enforcing "no raw new in cpp/" |
| PR | Scope | Status |
|---|---|---|
| #31-1 | This plan | shipped |
| #31-2 | Stage 1 — `address.cc`, `space.cc`, `rangeutil.cc` (audit's "range.cc" target) | shipped: the three files were already raw-`new`-free in tree; the `gradle cppRaiiAudit` per-file gate (see [`gradle/cppRaiiAudit.gradle`](../../gradle/cppRaiiAudit.gradle)) was added to fail CI on any regression. Wired into `.github/workflows/build-ghidra.yml` alongside `ignoreAudit` and `objectInputStreamAudit`. |
| #31-3 | Stage 2 — `marshal.cc`, `xml.cc` | open |
| #31-4 | Stage 3 — `database.cc`, `comment.cc`, `cover.cc` | open |
| #31-5 | Stage 4 — `type.cc`, `userop.cc` | open |
| #31-6 | Stage 5 — pcode core | open |
| #31-7 | Stage 6 — analysis passes | open |
| #31-8 | Stage 7 — Sleigh runtime (parallel to #31-7) | open |
| #31-9 | Stage 8 — mop-up | open |
| #31-10 | Tree-wide CI lint enforcing "no raw new in cpp/" | open — `cppRaiiAudit` foundation laid in #31-2 (per-file gate); #31-10 generalises to all `decompile/cpp/**.cc` |

Each stage is reviewed by at least one decompiler maintainer
(see [MAINTAINERS.md](../../MAINTAINERS.md)).
Expand Down
95 changes: 95 additions & 0 deletions gradle/cppRaiiAudit.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* ###
* C++ RAII audit task — protected-file gate.
*
* Addresses Rec 31 #31-2 of the 2026-05-21 audit. See
* docs/decompiler/RAII_MIGRATION.md for the migration plan and
* docs/decompiler/CPP20_ADOPTION.md for the language-stage context.
*
* Walks a fixed list of decompiler C++ files asserting they contain
* no raw `new <ClassName>(...)` or `new <ClassName>[...]` allocations.
* The RAII idiom we want is `std::make_unique<T>(...)` (or `std::make_shared`,
* or stack/value allocation). Smart-pointer factories never produce raw
* pointers to leak across the API boundary, so the audit forbids the
* raw form anywhere in the protected set.
*
* The protected set is intentionally small. Sprint 6 #31-2 brings the
* first three foundation files under the gate; later stages (#31-3,
* #31-4, ...) extend the set as more files are RAII-converted. The
* gate is per-file allowlist — anything not on the list is unaffected.
* The tree-wide "no raw new in cpp/" lint (#31-10 in RAII_MIGRATION.md)
* is a later, broader form of this same idea.
*
* Apply this from the root build.gradle:
* apply from: 'gradle/cppRaiiAudit.gradle'
*
* The task is named `cppRaiiAudit` at the root and is invoked as a
* dedicated CI step in `.github/workflows/build-ghidra.yml`.
*/

import java.util.regex.Pattern

// `new` keyword followed by an identifier and a `(`, `[`, or `<`
// opener. The `\b` word boundary keeps us from matching `renewable`
// or similar; the lookahead enforces an allocation site, not a
// general `new` mention (e.g., in comments / strings that survive
// the trim filter below).
final Pattern RAW_NEW_PATTERN = Pattern.compile(
'\\bnew\\s+[A-Za-z_][A-Za-z0-9_:]*\\s*[(\\[<]')

// Files under the RAII gate. Path-suffix match keeps the rule
// independent of the repo's root layout. Sprint 6 #31-2 starts with
// the address / space / rangeutil triangle that the audit named as
// foundation files; subsequent stages extend the set.
final Set<String> PROTECTED_FILES = [
'Ghidra/Features/Decompiler/src/decompile/cpp/address.cc',
'Ghidra/Features/Decompiler/src/decompile/cpp/space.cc',
'Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.cc',
] as Set

task cppRaiiAudit {
description = 'Verify protected decompiler C++ files contain no raw `new` allocations.'
group = 'verification'

doLast {
List<String> violations = []
List<String> missing = []
PROTECTED_FILES.each { String rel ->
File f = new File(rootDir, rel)
if (!f.exists()) {
missing.add(rel)
return
}
int lineNum = 0
f.eachLine('UTF-8') { String line ->
lineNum++
// Skip pure-comment lines — both `//` line-comments
// and `*` continuation lines inside `/* ... */` blocks.
// Same simple filter as objectInputStreamAudit; string-
// literal false positives can be fixed by the author.
String trimmed = line.trim()
if (trimmed.startsWith('//') || trimmed.startsWith('*')) {
return
}
def m = RAW_NEW_PATTERN.matcher(line)
if (m.find()) {
violations.add("${rel}:${lineNum} raw `new` allocation " +
"(use std::make_unique<T> or std::make_shared<T>)")
}
}
}

if (!missing.isEmpty()) {
logger.warn 'cppRaiiAudit: protected files missing from tree (audit list out of date):'
missing.each { logger.warn " ${it}" }
}
if (!violations.isEmpty()) {
logger.error '== C++ RAII audit failures =='
violations.each { logger.error " ${it}" }
throw new GradleException(
"${violations.size()} raw `new` allocation(s) in RAII-protected files. " +
"See docs/decompiler/RAII_MIGRATION.md (Rec 31 #31-2) — protected files " +
"must construct heap-owned objects via std::make_unique / std::make_shared.")
}
logger.lifecycle "cppRaiiAudit: ${PROTECTED_FILES.size()} protected file(s) clean."
}
}
Loading