A freshly released coding model can generate several C++ patch candidates in the time it takes to write a code review. When generation is cheap, the review cost becomes the bottleneck. A patch that compiles and passes the visible unit test can still carry undefined behavior, a data race, or a resource leak that appears only under a sanitizer.
This article describes a reproducible four-tier gate for model-generated C++ patches. The gate treats model output as untrusted input and runs it through compile checks, AddressSanitizer/UndefinedBehaviorSanitizer, ThreadSanitizer, and a repeated stress run. MonkeyCode's free model access and free server option fit into two specific slots: producing patch candidates and running slower isolation jobs. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
The pipeline is intentionally model-agnostic. Commands do not need model names because the gate only cares about the diff and the executable.
Why a tiered gate is useful
A single "does it pass the test?" question is too weak for C++ because:
- Undefined behavior can survive normal compilation and unit tests.
- Data races often appear only under ThreadSanitizer with a suitable interleaving.
- Leaks and use-after-free often appear only under AddressSanitizer.
- A cheap model can produce many plausible patches, so the reviewer needs a mechanical first pass.
The tiers below are ordered from cheapest to most expensive so that bad patches fail before consuming a remote runner slot.
The four tiers
| Tier | Question | Primary signal | Default environment |
|---|---|---|---|
| 0 | Does the patch compile cleanly? |
-Werror exit code |
local |
| 1 | Does it trip ASan/UBSan? | sanitizer exit code | local |
| 2 | Does it trip TSan? | sanitizer exit code | local or free server |
| 3 | Does it survive repeated runs? | repeated exit codes | free server |
Tier 3 is where a disposable free server is most relevant. It can run loops that would be inconvenient on a laptop, such as repeated sanitizer runs, larger inputs, or a stress build that takes several minutes.
Workspace layout
gate/
config.env
gate.sh
run_remote.sh
fixtures/
use_after_free.cpp
data_race.cpp
config.env keeps toolchain and runner settings separate from logic.
# config.env
CXX=g++
STD=c++20
RUNNER=
REMOTE=0
Tier 0: compiler as first filter
Tier 0 is a deliberately strict compile. Warnings are errors, and the output goes to a temporary object file so the executable is not trusted yet.
$CXX -std="$STD" -Wall -Wextra -Werror -c "$CANDIDATE" -o /tmp/gate_t0.o
A patch that fails here should return to the model or the reviewer immediately. The generated code has not earned the right to run.
Tier 1: ASan and UBSan
The following command builds with AddressSanitizer and UndefinedBehaviorSanitizer and runs the result once.
$CXX -std="$STD" -fsanitize=address,undefined -g -O1 "$CANDIDATE" -o /tmp/gate_t1
/tmp/gate_t1 < /dev/null
A minimal fixture that passes Tier 0 but fails Tier 1 is shown below.
#include <iostream>
int main() {
int* p = new int(7);
delete p;
std::cout << *p << '\n'; // use-after-free
}
ASan reports the use-after-free and exits nonzero, which is exactly the signal the gate needs.
Tier 2: TSan
Tier 2 builds with ThreadSanitizer and runs a small repeat loop. This is where a remote runner starts to make sense.
$CXX -std="$STD" -fsanitize=thread -g -O1 "$CANDIDATE" -o /tmp/gate_t2
for i in 1 2 3; do /tmp/gate_t2 < /dev/null; done
A compact data race fixture is below.
#include <thread>
#include <vector>
int main() {
int counter = 0;
std::vector<std::thread> threads;
for (int i = 0; i < 8; ++i) {
threads.emplace_back([&] {
for (int j = 0; j < 1000; ++j) ++counter;
});
}
for (auto& t : threads) t.join();
return counter;
}
ThreadSanitizer reports the unsynchronized write to counter. The exact report may vary by toolchain, but the nonzero exit code is the gate's contract.
Tier 3: repeated stress on a disposable server
Tier 3 is a loop, not a proof. It exists to catch flakes and resource pressure that single runs miss. The example uses SSH because it is tool-agnostic; an operator can replace the transport with whatever the free server option exposes.
gate.sh:
#!/usr/bin/env bash
set -euo pipefail
CXX="${CXX:-g++}"
STD="${STD:-c++20}"
CANDIDATE="${1:?usage: gate.sh candidate.cpp}"
# Tier 0: compile with warnings as errors
$CXX -std="$STD" -Wall -Wextra -Werror -c "$CANDIDATE" -o /tmp/gate_t0.o
# Tier 1: ASan + UBSan
$CXX -std="$STD" -fsanitize=address,undefined -g -O1 "$CANDIDATE" -o /tmp/gate_t1
/tmp/gate_t1 < /dev/null
# Tier 2: TSan with a small repeat count
$CXX -std="$STD" -fsanitize=thread -g -O1 "$CANDIDATE" -o /tmp/gate_t2
for i in 1 2 3; do /tmp/gate_t2 < /dev/null; done
echo "gate passed"
run_remote.sh:
#!/usr/bin/env bash
set -euo pipefail
source ./config.env
if [[ "${REMOTE}" == "1" ]]; then
test -n "${RUNNER}" || { echo "RUNNER is required when REMOTE=1" >&2; exit 2; }
scp "$1" "${RUNNER}:/tmp/gate/"
ssh "${RUNNER}" "cd /tmp/gate && CXX=${CXX} STD=${STD} bash gate.sh $(basename "$1")"
else
bash gate.sh "$1"
fi
Usage:
chmod +x gate.sh run_remote.sh
./run_remote.sh fixtures/use_after_free.cpp # fails at Tier 1
REMOTE=1 RUNNER=runner-host ./run_remote.sh fixtures/data_race.cpp
The snippets are reference implementations, not an executed benchmark. Test them in a container before using them in CI.
Limitations
- Sanitizers catch only what the input actually exercises. A green run is not a proof of correctness.
- A free server may be queued, reset between jobs, or time-limited. Do not assume persistent artifacts.
- The SSH example is only a transport sketch; the actual free server option may use a different interface.
- The gate does not replace human code review. It reduces the number of plausible patches that reach the reviewer.
Who should not use this approach
Teams with the following constraints should keep the entire pipeline on-premises:
- Patches touch private keys, credentials, or regulated data.
- Compliance rules forbid third-party model or runner access.
- The codebase depends on hardware-specific behavior that sanitizers cannot model.
- The project requires a deterministic, auditable execution environment for every patch.
For those cases, the same tiered script is still useful, but both generation and execution should run on infrastructure the team controls.
The point of the gate is not to trust the model output. It is to make the first review step cheap and reproducible before a human spends time on a plausible but unsafe patch.
Where cheap model access and a disposable remote runner are already available, the same script can be pointed at them with a configuration change. The gate remains useful even if those options are replaced.
Top comments (0)