1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub enum BugSeverity {
9 Critical,
11 High,
13 Medium,
15 FalsePositive,
17}
18
19impl fmt::Display for BugSeverity {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 Self::Critical => write!(f, "P0-CRITICAL"),
23 Self::High => write!(f, "P1-HIGH"),
24 Self::Medium => write!(f, "P2-MEDIUM"),
25 Self::FalsePositive => write!(f, "FALSE-POSITIVE"),
26 }
27 }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
32pub enum PtxBugClass {
33 SharedMemU64Addressing,
35 LoopBranchToEnd,
37 MissingBarrierSync,
39 EarlyExitBeforeBarrier,
41 NonInPlaceLoopAccumulator,
43 RegisterSpills,
45 HighRegisterPressure,
47 PredicateOverflow,
49 PlaceholderCode,
51 EmptyLoopBody,
53 MissingBoundsCheck,
55 RedundantMoves,
57 UnoptimizedMemoryPattern,
59 DeadCode,
61 InvalidSyntaxAccepted,
63 MissingEntryPoint,
65}
66
67impl PtxBugClass {
68 #[must_use]
70 pub fn severity(&self) -> BugSeverity {
71 match self {
72 Self::SharedMemU64Addressing
73 | Self::LoopBranchToEnd
74 | Self::MissingBarrierSync
75 | Self::EarlyExitBeforeBarrier => BugSeverity::Critical,
76
77 Self::NonInPlaceLoopAccumulator
78 | Self::RegisterSpills
79 | Self::HighRegisterPressure
80 | Self::PredicateOverflow
81 | Self::PlaceholderCode
82 | Self::EmptyLoopBody
83 | Self::MissingBoundsCheck => BugSeverity::High,
84
85 Self::RedundantMoves | Self::UnoptimizedMemoryPattern | Self::DeadCode => {
86 BugSeverity::Medium
87 }
88
89 Self::InvalidSyntaxAccepted | Self::MissingEntryPoint => BugSeverity::FalsePositive,
90 }
91 }
92
93 #[must_use]
95 pub fn code(&self) -> &'static str {
96 match self {
97 Self::SharedMemU64Addressing => "SHARED_U64",
98 Self::LoopBranchToEnd => "LOOP_BRANCH_END",
99 Self::MissingBarrierSync => "MISSING_BARRIER",
100 Self::EarlyExitBeforeBarrier => "EARLY_EXIT_BARRIER",
101 Self::NonInPlaceLoopAccumulator => "NON_INPLACE_ACCUM",
102 Self::RegisterSpills => "REG_SPILLS",
103 Self::HighRegisterPressure => "HIGH_REG_PRESSURE",
104 Self::PredicateOverflow => "PRED_OVERFLOW",
105 Self::PlaceholderCode => "PLACEHOLDER_CODE",
106 Self::EmptyLoopBody => "EMPTY_LOOP",
107 Self::MissingBoundsCheck => "NO_BOUNDS_CHECK",
108 Self::RedundantMoves => "REDUNDANT_MOV",
109 Self::UnoptimizedMemoryPattern => "UNOPT_MEM",
110 Self::DeadCode => "DEAD_CODE",
111 Self::InvalidSyntaxAccepted => "INVALID_SYNTAX",
112 Self::MissingEntryPoint => "NO_ENTRY",
113 }
114 }
115}
116
117impl fmt::Display for PtxBugClass {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(f, "{}", self.code())
120 }
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct PtxBug {
126 pub class: PtxBugClass,
128 pub line: usize,
130 pub instruction: String,
132 pub message: String,
134 pub fix: Option<String>,
136}
137
138impl PtxBug {
139 #[must_use]
141 pub fn severity(&self) -> BugSeverity {
142 self.class.severity()
143 }
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
148pub struct PtxBugReport {
149 pub kernel_name: Option<String>,
151 pub bugs: Vec<PtxBug>,
153 pub lines_analyzed: usize,
155 pub strict_mode: bool,
157}
158
159impl PtxBugReport {
160 #[must_use]
162 pub fn is_valid(&self) -> bool {
163 !self
164 .bugs
165 .iter()
166 .any(|b| b.severity() == BugSeverity::Critical)
167 }
168
169 #[must_use]
171 pub fn has_bugs(&self) -> bool {
172 !self.bugs.is_empty()
173 }
174
175 #[must_use]
177 pub fn count_by_severity(&self, severity: BugSeverity) -> usize {
178 self.bugs
179 .iter()
180 .filter(|b| b.severity() == severity)
181 .count()
182 }
183
184 #[must_use]
186 pub fn has_bug(&self, class: &PtxBugClass) -> bool {
187 self.bugs.iter().any(|b| &b.class == class)
188 }
189
190 #[must_use]
192 pub fn bugs_of_class(&self, class: &PtxBugClass) -> Vec<&PtxBug> {
193 self.bugs.iter().filter(|b| &b.class == class).collect()
194 }
195
196 #[must_use]
198 pub fn format_report(&self) -> String {
199 let mut output = String::new();
200
201 output.push_str(
202 "╔══════════════════════════════════════════════════════════════════════════════╗\n",
203 );
204 output.push_str(
205 "║ PTX BUG HUNTING REPORT ║\n",
206 );
207 output.push_str(
208 "╚══════════════════════════════════════════════════════════════════════════════╝\n\n",
209 );
210
211 if let Some(name) = &self.kernel_name {
212 output.push_str(&format!("Kernel: {}\n", name));
213 }
214 output.push_str(&format!("PTX Lines Analyzed: {}\n\n", self.lines_analyzed));
215
216 let critical = self.count_by_severity(BugSeverity::Critical);
217 let high = self.count_by_severity(BugSeverity::High);
218 let medium = self.count_by_severity(BugSeverity::Medium);
219 let false_pos = self.count_by_severity(BugSeverity::FalsePositive);
220
221 output.push_str(&format!("P0 CRITICAL BUGS: {}\n", critical));
223 if critical > 0 {
224 output.push_str("──────────────────\n");
225 for (i, bug) in self
226 .bugs
227 .iter()
228 .filter(|b| b.severity() == BugSeverity::Critical)
229 .enumerate()
230 {
231 output.push_str(&format!(" BUG-{:03}: {}\n", i + 1, bug.class));
232 if bug.line > 0 {
233 output.push_str(&format!(" Line {}: {}\n", bug.line, bug.instruction));
234 }
235 output.push_str(&format!(" Impact: {}\n", bug.message));
236 if let Some(fix) = &bug.fix {
237 output.push_str(&format!(" Fix: {}\n", fix));
238 }
239 output.push('\n');
240 }
241 }
242
243 output.push_str(&format!("\nP1 HIGH BUGS: {}\n", high));
245 if high > 0 {
246 output.push_str("─────────────────\n");
247 for bug in self
248 .bugs
249 .iter()
250 .filter(|b| b.severity() == BugSeverity::High)
251 {
252 output.push_str(&format!(" {}: {}\n", bug.class, bug.message));
253 }
254 }
255
256 output.push_str(&format!("\nP2 MEDIUM BUGS: {}\n", medium));
258 if medium > 0 {
259 output.push_str("─────────────────\n");
260 for bug in self
261 .bugs
262 .iter()
263 .filter(|b| b.severity() == BugSeverity::Medium)
264 {
265 output.push_str(&format!(" {}: {}\n", bug.class, bug.message));
266 }
267 }
268
269 output.push_str(&format!("\nFALSE POSITIVES DETECTED: {}\n", false_pos));
271
272 output.push_str("\nSUMMARY\n═══════\n");
274 output.push_str(&format!(" Total Bugs: {}\n", self.bugs.len()));
275 output.push_str(&format!(" P0 Critical: {}", critical));
276 if critical > 0 {
277 output.push_str(" ← BLOCKS RELEASE");
278 }
279 output.push('\n');
280 output.push_str(&format!(" P1 High: {}\n", high));
281 output.push_str(&format!(" P2 Medium: {}\n", medium));
282
283 output
284 }
285}