recordPathCrash writes a JSON artifact capturing the data + path that triggered a panic, so the crash is reproducible outside the fuzzer. Deduplicated by signature (panic-msg + innermost parser frame) so a single crash class produces a single file.
(target string, panicVal interface{}, stack, data, path []byte)
| 64 | // Deduplicated by signature (panic-msg + innermost parser frame) so a |
| 65 | // single crash class produces a single file. |
| 66 | func recordPathCrash(target string, panicVal interface{}, stack, data, path []byte) { |
| 67 | panicMsg := fmt.Sprintf("%v", panicVal) |
| 68 | var key strings.Builder |
| 69 | key.WriteString(panicMsg) |
| 70 | for _, line := range strings.Split(string(stack), "\n") { |
| 71 | if strings.Contains(line, "github.com/buger/jsonparser/") && |
| 72 | !strings.Contains(line, "path_fuzz_test.go") && |
| 73 | !strings.Contains(line, "/fuzz.go:") && |
| 74 | !strings.Contains(line, "fuzz_native_test.go") { |
| 75 | key.WriteString("|") |
| 76 | key.WriteString(strings.TrimSpace(line)) |
| 77 | break |
| 78 | } |
| 79 | } |
| 80 | sum := sha256.Sum256([]byte(key.String())) |
| 81 | sig := hex.EncodeToString(sum[:])[:12] |
| 82 | fname := filepath.Join(pathFuzzCrashDir, target+"_"+sig+".json") |
| 83 | if _, err := os.Stat(fname); err == nil { |
| 84 | return // already recorded — dedup |
| 85 | } |
| 86 | f, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644) |
| 87 | if err != nil { |
| 88 | return |
| 89 | } |
| 90 | defer f.Close() |
| 91 | dataCopy := make([]byte, len(data)) |
| 92 | copy(dataCopy, data) |
| 93 | pathCopy := make([]byte, len(path)) |
| 94 | copy(pathCopy, path) |
| 95 | enc := json.NewEncoder(f) |
| 96 | enc.SetIndent("", " ") |
| 97 | _ = enc.Encode(map[string]interface{}{ |
| 98 | "target": target, |
| 99 | "sig": sig, |
| 100 | "panic": panicMsg, |
| 101 | "stack": string(stack), |
| 102 | "data": string(dataCopy), |
| 103 | "path": string(pathCopy), |
| 104 | "components": splitPathComponents(pathCopy), |
| 105 | }) |
| 106 | } |
| 107 | |
| 108 | // splitPathComponents interprets the fuzz path bytes as a '/'-separated |
| 109 | // list of key components. Empty segments (from "", "a/", "/a", "a//b", |
no test coverage detected