mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
[pitboss/grind] deferred session-0010 (20260516T052512Z-20f8)
This commit is contained in:
parent
76de47fb6b
commit
c162c638a2
3 changed files with 167 additions and 20 deletions
|
|
@ -412,6 +412,7 @@ fn generate_main_go(spec: &HarnessSpec, shape: GoShape) -> String {
|
|||
let pre_call = pre_call_setup(spec);
|
||||
let imports = imports_for_shape(shape);
|
||||
let invocation = invoke_for_shape(spec, shape, &entry_fn);
|
||||
let shim = probe_shim();
|
||||
|
||||
format!(
|
||||
r#"// Nyx dynamic harness — auto-generated, do not edit (Phase 15 — GoShape::{shape:?}).
|
||||
|
|
@ -419,10 +420,12 @@ package main
|
|||
|
||||
import (
|
||||
{imports})
|
||||
|
||||
{shim}
|
||||
func main() {{
|
||||
payload := nyxPayload()
|
||||
_ = payload
|
||||
__nyx_install_crash_guard("{entry_fn}")
|
||||
defer __nyx_recover_crash("{entry_fn}")()
|
||||
{pre_call}{invocation}
|
||||
}}
|
||||
|
||||
|
|
@ -442,27 +445,57 @@ func nyxPayload() string {{
|
|||
imports = imports,
|
||||
pre_call = pre_call,
|
||||
invocation = invocation,
|
||||
shim = shim,
|
||||
entry_fn = entry_fn,
|
||||
)
|
||||
}
|
||||
|
||||
fn imports_for_shape(shape: GoShape) -> &'static str {
|
||||
match shape {
|
||||
GoShape::Generic => {
|
||||
"\t\"encoding/base64\"\n\t\"os\"\n\n\t\"nyx-harness/entry\"\n"
|
||||
}
|
||||
GoShape::HttpHandlerFunc => {
|
||||
"\t\"encoding/base64\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\n\t\"nyx-harness/entry\"\n"
|
||||
}
|
||||
GoShape::GinHandler => {
|
||||
"\t\"encoding/base64\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"strings\"\n\n\t\"nyx-harness/entry\"\n\t\"nyx-harness/entry/gin\"\n"
|
||||
}
|
||||
GoShape::FlagParseCli => {
|
||||
"\t\"encoding/base64\"\n\t\"os\"\n\n\t\"nyx-harness/entry\"\n"
|
||||
}
|
||||
GoShape::FuzzVariadic => {
|
||||
"\t\"encoding/base64\"\n\t\"os\"\n\n\t\"nyx-harness/entry\"\n"
|
||||
}
|
||||
/// Imports required by the spliced probe shim. Always present, deduped
|
||||
/// against per-shape additions in [`imports_for_shape`].
|
||||
const SHIM_IMPORTS: &[&str] = &[
|
||||
"encoding/json",
|
||||
"os/signal",
|
||||
"strings",
|
||||
"syscall",
|
||||
"time",
|
||||
];
|
||||
|
||||
fn imports_for_shape(shape: GoShape) -> String {
|
||||
let stdlib_base: &[&str] = &["encoding/base64", "os"];
|
||||
let shape_extras: &[&str] = match shape {
|
||||
GoShape::Generic | GoShape::FlagParseCli | GoShape::FuzzVariadic => &[],
|
||||
GoShape::HttpHandlerFunc => &["net/http", "net/http/httptest"],
|
||||
GoShape::GinHandler => &["net/http", "net/http/httptest"],
|
||||
};
|
||||
let local_pkgs: &[&str] = match shape {
|
||||
GoShape::GinHandler => &["nyx-harness/entry", "nyx-harness/entry/gin"],
|
||||
_ => &["nyx-harness/entry"],
|
||||
};
|
||||
|
||||
let mut stdlib: Vec<&str> = stdlib_base
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(shape_extras.iter().copied())
|
||||
.chain(SHIM_IMPORTS.iter().copied())
|
||||
.collect();
|
||||
stdlib.sort_unstable();
|
||||
stdlib.dedup();
|
||||
|
||||
let mut out = String::new();
|
||||
for path in &stdlib {
|
||||
out.push('\t');
|
||||
out.push('"');
|
||||
out.push_str(path);
|
||||
out.push_str("\"\n");
|
||||
}
|
||||
out.push('\n');
|
||||
for path in local_pkgs {
|
||||
out.push('\t');
|
||||
out.push('"');
|
||||
out.push_str(path);
|
||||
out.push_str("\"\n");
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn pre_call_setup(spec: &HarnessSpec) -> String {
|
||||
|
|
@ -772,4 +805,45 @@ mod tests {
|
|||
let src = generate_main_go(&spec, GoShape::FuzzVariadic);
|
||||
assert!(src.contains("entry.FuzzHandle([]byte(payload))"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_splices_probe_shim_and_installs_crash_guard() {
|
||||
let spec = make_spec(PayloadSlot::Param(0));
|
||||
let h = emit(&spec).unwrap();
|
||||
assert!(
|
||||
h.source.contains("__nyx_probe shim (Phase 06 — Track C.1"),
|
||||
"probe_shim banner missing from generated main.go — splicing regressed",
|
||||
);
|
||||
assert!(
|
||||
h.source.contains("func __nyx_install_crash_guard("),
|
||||
"install_crash_guard definition missing from generated main.go",
|
||||
);
|
||||
assert!(
|
||||
h.source.contains("__nyx_install_crash_guard(\"HandleRequest\")"),
|
||||
"install_crash_guard call site missing or wrong callee in main()",
|
||||
);
|
||||
let install_pos = h
|
||||
.source
|
||||
.find("__nyx_install_crash_guard(\"HandleRequest\")")
|
||||
.unwrap();
|
||||
let payload_pos = h.source.find("payload := nyxPayload()").unwrap();
|
||||
let invoke_pos = h.source.find("entry.HandleRequest(payload)").unwrap();
|
||||
assert!(
|
||||
payload_pos < install_pos && install_pos < invoke_pos,
|
||||
"install_crash_guard ordering wrong: payload_pos={payload_pos} install_pos={install_pos} invoke_pos={invoke_pos}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_includes_shim_imports_in_import_block() {
|
||||
let spec = make_spec(PayloadSlot::Param(0));
|
||||
let h = emit(&spec).unwrap();
|
||||
for path in SHIM_IMPORTS {
|
||||
let quoted = format!("\"{path}\"");
|
||||
assert!(
|
||||
h.source.contains("ed),
|
||||
"expected shim-required import {quoted} in generated main.go",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,11 +359,13 @@ fn generate_source(spec: &HarnessSpec, shape: PhpShape) -> String {
|
|||
let pre_call = build_pre_call(spec, shape);
|
||||
let entry_block = build_entry_block(shape);
|
||||
let call_expr = build_call_expr(spec, shape, entry_fn);
|
||||
let shim = probe_shim();
|
||||
let crash_callee = if entry_fn.is_empty() { "main" } else { entry_fn.as_str() };
|
||||
|
||||
format!(
|
||||
r#"<?php
|
||||
// Nyx dynamic harness — auto-generated, do not edit (Phase 15 — PhpShape::{shape:?}).
|
||||
|
||||
{shim}
|
||||
// ── Payload loading ────────────────────────────────────────────────────────────
|
||||
function nyx_payload(): string {{
|
||||
$v = getenv('NYX_PAYLOAD');
|
||||
|
|
@ -379,6 +381,12 @@ function nyx_payload(): string {{
|
|||
|
||||
$payload = nyx_payload();
|
||||
|
||||
// Phase 08 sink-site signal handler: install AFTER payload decode so a crash
|
||||
// inside `nyx_payload` writes no Crash probe and routes the verifier to
|
||||
// `Inconclusive(UnrelatedCrash)`. A fatal-error inside the entry call below
|
||||
// DOES fire the handler and writes a Crash probe to `NYX_PROBE_PATH`.
|
||||
__nyx_install_crash_guard('{crash_callee}');
|
||||
|
||||
// ── Pre-call setup ─────────────────────────────────────────────────────────────
|
||||
{pre_call}
|
||||
// ── Entry include ─────────────────────────────────────────────────────────────
|
||||
|
|
@ -397,6 +405,8 @@ try {{
|
|||
pre_call = pre_call,
|
||||
entry_block = entry_block,
|
||||
call_expr = call_expr,
|
||||
shim = shim,
|
||||
crash_callee = crash_callee,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -673,4 +683,33 @@ mod tests {
|
|||
assert!(src.contains("require_once"));
|
||||
assert!(src.contains("$result = null"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_splices_probe_shim_and_installs_crash_guard() {
|
||||
let spec = make_spec(PayloadSlot::Param(0));
|
||||
let h = emit(&spec).unwrap();
|
||||
assert!(
|
||||
h.source.contains("__nyx_probe shim (Phase 06 — Track C.1"),
|
||||
"probe_shim banner missing from generated harness.php — splicing regressed",
|
||||
);
|
||||
assert!(
|
||||
h.source
|
||||
.contains("function __nyx_install_crash_guard(string $sinkCallee)"),
|
||||
"install_crash_guard definition missing from generated harness.php",
|
||||
);
|
||||
assert!(
|
||||
h.source.contains("__nyx_install_crash_guard('login');"),
|
||||
"install_crash_guard call site missing or wrong callee in harness body",
|
||||
);
|
||||
let install_pos = h
|
||||
.source
|
||||
.find("__nyx_install_crash_guard('login');")
|
||||
.unwrap();
|
||||
let payload_pos = h.source.find("$payload = nyx_payload();").unwrap();
|
||||
let invoke_pos = h.source.find("login($payload)").unwrap();
|
||||
assert!(
|
||||
payload_pos < install_pos && install_pos < invoke_pos,
|
||||
"install_crash_guard ordering wrong: payload_pos={payload_pos} install_pos={install_pos} invoke_pos={invoke_pos}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,10 +351,12 @@ fn generate_source(spec: &HarnessSpec, shape: RubyShape) -> String {
|
|||
let entry_fn = &spec.entry_name;
|
||||
let pre_call = build_pre_call(spec);
|
||||
let invocation = invoke_for_shape(spec, shape, entry_fn);
|
||||
let shim = probe_shim();
|
||||
let crash_callee = if entry_fn.is_empty() { "main" } else { entry_fn.as_str() };
|
||||
|
||||
format!(
|
||||
r#"# Nyx dynamic harness — auto-generated, do not edit (Phase 15 — RubyShape::{shape:?}).
|
||||
|
||||
{shim}
|
||||
# ── Payload loading ──────────────────────────────────────────────────────────
|
||||
def nyx_payload
|
||||
v = ENV['NYX_PAYLOAD']
|
||||
|
|
@ -372,6 +374,12 @@ def nyx_payload
|
|||
end
|
||||
|
||||
$nyx_payload = nyx_payload
|
||||
|
||||
# Phase 08 sink-site signal trap: install AFTER payload decode so a crash
|
||||
# inside `nyx_payload` writes no Crash probe and routes the verifier to
|
||||
# `Inconclusive(UnrelatedCrash)`. A fatal signal inside the entry call
|
||||
# below DOES fire the handler and writes a Crash probe to `NYX_PROBE_PATH`.
|
||||
__nyx_install_crash_guard('{crash_callee}')
|
||||
{pre_call}
|
||||
# ── Sinatra route registry ──────────────────────────────────────────────────
|
||||
$nyx_sinatra_routes ||= []
|
||||
|
|
@ -734,4 +742,30 @@ mod tests {
|
|||
assert_eq!(parse_first_class_name("class Bar < Base\nend\n"), Some("Bar".to_owned()));
|
||||
assert_eq!(parse_first_class_name("def foo\nend\n"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn emit_splices_probe_shim_and_installs_crash_guard() {
|
||||
let spec = make_spec(PayloadSlot::Param(0));
|
||||
let h = emit(&spec).unwrap();
|
||||
assert!(
|
||||
h.source.contains("__nyx_probe shim (Phase 06 — Track C.1"),
|
||||
"probe_shim banner missing from generated harness.rb — splicing regressed",
|
||||
);
|
||||
assert!(
|
||||
h.source.contains("def __nyx_install_crash_guard(sink_callee)"),
|
||||
"install_crash_guard definition missing from generated harness.rb",
|
||||
);
|
||||
assert!(
|
||||
h.source.contains("__nyx_install_crash_guard('login')"),
|
||||
"install_crash_guard call site missing or wrong callee in harness body",
|
||||
);
|
||||
let install_pos = h.source.find("__nyx_install_crash_guard('login')").unwrap();
|
||||
let payload_pos = h.source.find("$nyx_payload = nyx_payload").unwrap();
|
||||
// The invocation is `login($nyx_payload)` for the default Generic shape.
|
||||
let invoke_pos = h.source.find("login($nyx_payload)").unwrap();
|
||||
assert!(
|
||||
payload_pos < install_pos && install_pos < invoke_pos,
|
||||
"install_crash_guard ordering wrong: payload_pos={payload_pos} install_pos={install_pos} invoke_pos={invoke_pos}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue