1use super::program::{entities::{JvmMethod, JvmProgram}, instructions::JvmInstruction, types::JvmVerificationType};
2
3#[derive(Debug, Clone)]
5pub struct ValidationError {
6 pub message: String,
8 pub instruction_index: usize,
10 pub detail: Option<String>,
12}
13
14impl ValidationError {
15 pub fn new(message: String, instruction_index: usize, detail: Option<String>) -> Self {
17 Self { message, instruction_index, detail }
18 }
19}
20
21pub struct BytecodeValidator<'a> {
23 stack: Vec<JvmVerificationType>,
25 locals: Vec<Option<JvmVerificationType>>,
27 method: &'a JvmMethod,
29 errors: Vec<ValidationError>,
31 current_index: usize,
33}
34
35impl<'a> BytecodeValidator<'a> {
36 pub fn new(method: &'a JvmMethod) -> Self {
38 let max_locals = method.max_locals as usize;
39 Self {
40 stack: Vec::new(),
41 locals: vec![None; max_locals],
42 method,
43 errors: Vec::new(),
44 current_index: 0,
45 }
46 }
47
48 pub fn validate(&mut self) -> Vec<ValidationError> {
50 self.initialize_locals();
52
53 for (index, instruction) in self.method.instructions.iter().enumerate() {
55 self.current_index = index;
56 self.validate_instruction(instruction);
57 }
58
59 self.check_return_instruction();
61
62 self.errors.clone()
63 }
64
65 fn initialize_locals(&mut self) {
67 let descriptor = &self.method.descriptor;
69 let param_start = descriptor.find('(').unwrap_or(0) + 1;
70 let param_end = descriptor.find(')').unwrap_or(descriptor.len());
71 let params_str = &descriptor[param_start..param_end];
72
73 let mut param_index = 0;
74 let mut i = 0;
75
76 while i < params_str.len() {
77 let ch = params_str.chars().nth(i).unwrap();
78 match ch {
79 'B' | 'C' | 'F' | 'I' | 'S' | 'Z' => {
80 self.locals[param_index] = Some(JvmVerificationType::Integer);
82 param_index += 1;
83 i += 1;
84 }
85 'D' | 'J' => {
86 self.locals[param_index] = Some(if ch == 'D' {
88 JvmVerificationType::Double
89 } else {
90 JvmVerificationType::Long
91 });
92 param_index += 2;
93 i += 1;
94 }
95 'L' => {
96 let end = params_str.find(';').unwrap_or(i + 1);
98 let class_name = ¶ms_str[i + 1..end];
99 self.locals[param_index] = Some(JvmVerificationType::Object {
100 class_name: class_name.to_string(),
101 });
102 param_index += 1;
103 i = end + 1;
104 }
105 '[' => {
106 let mut array_depth = 1;
108 let mut j = i + 1;
109 while j < params_str.len() && array_depth > 0 {
110 if params_str.chars().nth(j).unwrap() == '[' {
111 array_depth += 1;
112 } else if params_str.chars().nth(j).unwrap() == ';' {
113 array_depth -= 1;
114 } else if array_depth == 1 {
115 array_depth = 0;
116 }
117 j += 1;
118 }
119 self.locals[param_index] = Some(JvmVerificationType::Object {
120 class_name: params_str[i..j].to_string(),
121 });
122 param_index += 1;
123 i = j;
124 }
125 _ => i += 1,
126 }
127 }
128
129 if !self.method.access_flags.is_static {
131 for i in (1..self.locals.len()).rev() {
133 if i + 1 < self.locals.len() {
134 self.locals[i + 1] = self.locals[i].clone();
135 }
136 }
137 if !self.locals.is_empty() {
139 self.locals[0] = Some(JvmVerificationType::Object {
140 class_name: self.method.name.split('.').last().unwrap_or("").to_string(),
141 });
142 }
143 }
144 }
145
146 fn validate_instruction(&mut self, instruction: &JvmInstruction) {
148 match instruction {
149 JvmInstruction::Nop => {}
150 JvmInstruction::AconstNull => {
151 self.stack.push(JvmVerificationType::Null);
152 }
153 JvmInstruction::IconstM1 | JvmInstruction::Iconst0 | JvmInstruction::Iconst1 |
154 JvmInstruction::Iconst2 | JvmInstruction::Iconst3 | JvmInstruction::Iconst4 |
155 JvmInstruction::Iconst5 => {
156 self.stack.push(JvmVerificationType::Integer);
157 }
158 JvmInstruction::Lconst0 | JvmInstruction::Lconst1 => {
159 self.stack.push(JvmVerificationType::Long);
160 }
161 JvmInstruction::Fconst0 | JvmInstruction::Fconst1 | JvmInstruction::Fconst2 => {
162 self.stack.push(JvmVerificationType::Float);
163 }
164 JvmInstruction::Dconst0 | JvmInstruction::Dconst1 => {
165 self.stack.push(JvmVerificationType::Double);
166 }
167 JvmInstruction::Bipush { .. } | JvmInstruction::Sipush { .. } => {
168 self.stack.push(JvmVerificationType::Integer);
169 }
170 JvmInstruction::Ldc { .. } | JvmInstruction::LdcW { .. } => {
171 self.stack.push(JvmVerificationType::Integer);
173 }
174 JvmInstruction::Ldc2W { .. } => {
175 self.stack.push(JvmVerificationType::Long);
177 }
178 JvmInstruction::Iload { index } => {
179 self.validate_load_instruction(*index, JvmVerificationType::Integer);
180 }
181 JvmInstruction::Iload0 => self.validate_load_instruction(0, JvmVerificationType::Integer),
182 JvmInstruction::Iload1 => self.validate_load_instruction(1, JvmVerificationType::Integer),
183 JvmInstruction::Iload2 => self.validate_load_instruction(2, JvmVerificationType::Integer),
184 JvmInstruction::Iload3 => self.validate_load_instruction(3, JvmVerificationType::Integer),
185 JvmInstruction::Lload { index } => {
186 self.validate_load_instruction(*index, JvmVerificationType::Long);
187 }
188 JvmInstruction::Lload0 => self.validate_load_instruction(0, JvmVerificationType::Long),
189 JvmInstruction::Lload1 => self.validate_load_instruction(1, JvmVerificationType::Long),
190 JvmInstruction::Lload2 => self.validate_load_instruction(2, JvmVerificationType::Long),
191 JvmInstruction::Lload3 => self.validate_load_instruction(3, JvmVerificationType::Long),
192 JvmInstruction::Fload { index } => {
193 self.validate_load_instruction(*index, JvmVerificationType::Float);
194 }
195 JvmInstruction::Fload0 => self.validate_load_instruction(0, JvmVerificationType::Float),
196 JvmInstruction::Fload1 => self.validate_load_instruction(1, JvmVerificationType::Float),
197 JvmInstruction::Fload2 => self.validate_load_instruction(2, JvmVerificationType::Float),
198 JvmInstruction::Fload3 => self.validate_load_instruction(3, JvmVerificationType::Float),
199 JvmInstruction::Dload { index } => {
200 self.validate_load_instruction(*index, JvmVerificationType::Double);
201 }
202 JvmInstruction::Dload0 => self.validate_load_instruction(0, JvmVerificationType::Double),
203 JvmInstruction::Dload1 => self.validate_load_instruction(1, JvmVerificationType::Double),
204 JvmInstruction::Dload2 => self.validate_load_instruction(2, JvmVerificationType::Double),
205 JvmInstruction::Dload3 => self.validate_load_instruction(3, JvmVerificationType::Double),
206 JvmInstruction::Aload { index } => {
207 self.validate_load_instruction(*index, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
208 }
209 JvmInstruction::Aload0 => self.validate_load_instruction(0, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
210 JvmInstruction::Aload1 => self.validate_load_instruction(1, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
211 JvmInstruction::Aload2 => self.validate_load_instruction(2, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
212 JvmInstruction::Aload3 => self.validate_load_instruction(3, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
213 JvmInstruction::Iaload => {
214 self.validate_stack_size(2);
216 self.stack.pop(); self.stack.pop(); self.stack.push(JvmVerificationType::Integer);
219 }
220 JvmInstruction::Laload => {
221 self.validate_stack_size(2);
223 self.stack.pop(); self.stack.pop(); self.stack.push(JvmVerificationType::Long);
226 }
227 JvmInstruction::Faload => {
228 self.validate_stack_size(2);
230 self.stack.pop(); self.stack.pop(); self.stack.push(JvmVerificationType::Float);
233 }
234 JvmInstruction::Daload => {
235 self.validate_stack_size(2);
237 self.stack.pop(); self.stack.pop(); self.stack.push(JvmVerificationType::Double);
240 }
241 JvmInstruction::Aaload => {
242 self.validate_stack_size(2);
244 self.stack.pop(); self.stack.pop(); self.stack.push(JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
247 }
248 JvmInstruction::Baload | JvmInstruction::Caload | JvmInstruction::Saload => {
249 self.validate_stack_size(2);
251 self.stack.pop(); self.stack.pop(); self.stack.push(JvmVerificationType::Integer);
254 }
255 JvmInstruction::Istore { index } => {
256 self.validate_store_instruction(*index, JvmVerificationType::Integer);
257 }
258 JvmInstruction::Istore0 => self.validate_store_instruction(0, JvmVerificationType::Integer),
259 JvmInstruction::Istore1 => self.validate_store_instruction(1, JvmVerificationType::Integer),
260 JvmInstruction::Istore2 => self.validate_store_instruction(2, JvmVerificationType::Integer),
261 JvmInstruction::Istore3 => self.validate_store_instruction(3, JvmVerificationType::Integer),
262 JvmInstruction::Lstore { index } => {
263 self.validate_store_instruction(*index, JvmVerificationType::Long);
264 }
265 JvmInstruction::Lstore0 => self.validate_store_instruction(0, JvmVerificationType::Long),
266 JvmInstruction::Lstore1 => self.validate_store_instruction(1, JvmVerificationType::Long),
267 JvmInstruction::Lstore2 => self.validate_store_instruction(2, JvmVerificationType::Long),
268 JvmInstruction::Lstore3 => self.validate_store_instruction(3, JvmVerificationType::Long),
269 JvmInstruction::Fstore { index } => {
270 self.validate_store_instruction(*index, JvmVerificationType::Float);
271 }
272 JvmInstruction::Fstore0 => self.validate_store_instruction(0, JvmVerificationType::Float),
273 JvmInstruction::Fstore1 => self.validate_store_instruction(1, JvmVerificationType::Float),
274 JvmInstruction::Fstore2 => self.validate_store_instruction(2, JvmVerificationType::Float),
275 JvmInstruction::Fstore3 => self.validate_store_instruction(3, JvmVerificationType::Float),
276 JvmInstruction::Dstore { index } => {
277 self.validate_store_instruction(*index, JvmVerificationType::Double);
278 }
279 JvmInstruction::Dstore0 => self.validate_store_instruction(0, JvmVerificationType::Double),
280 JvmInstruction::Dstore1 => self.validate_store_instruction(1, JvmVerificationType::Double),
281 JvmInstruction::Dstore2 => self.validate_store_instruction(2, JvmVerificationType::Double),
282 JvmInstruction::Dstore3 => self.validate_store_instruction(3, JvmVerificationType::Double),
283 JvmInstruction::Astore { index } => {
284 self.validate_store_instruction(*index, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
285 }
286 JvmInstruction::Astore0 => self.validate_store_instruction(0, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
287 JvmInstruction::Astore1 => self.validate_store_instruction(1, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
288 JvmInstruction::Astore2 => self.validate_store_instruction(2, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
289 JvmInstruction::Astore3 => self.validate_store_instruction(3, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
290 JvmInstruction::Iastore => {
291 self.validate_stack_size(3);
293 self.stack.pop(); self.stack.pop(); self.stack.pop(); }
297 JvmInstruction::Lastore => {
298 self.validate_stack_size(3);
300 self.stack.pop(); self.stack.pop(); self.stack.pop(); }
304 JvmInstruction::Fastore => {
305 self.validate_stack_size(3);
307 self.stack.pop(); self.stack.pop(); self.stack.pop(); }
311 JvmInstruction::Dastore => {
312 self.validate_stack_size(3);
314 self.stack.pop(); self.stack.pop(); self.stack.pop(); }
318 JvmInstruction::Aastore => {
319 self.validate_stack_size(3);
321 self.stack.pop(); self.stack.pop(); self.stack.pop(); }
325 JvmInstruction::Bastore | JvmInstruction::Castore | JvmInstruction::Sastore => {
326 self.validate_stack_size(3);
328 self.stack.pop(); self.stack.pop(); self.stack.pop(); }
332 JvmInstruction::Pop => {
333 self.validate_stack_size(1);
334 self.stack.pop();
335 }
336 JvmInstruction::Pop2 => {
337 self.validate_stack_size(2);
338 self.stack.pop();
339 self.stack.pop();
340 }
341 JvmInstruction::Dup => {
342 self.validate_stack_size(1);
343 if let Some(top) = self.stack.last().cloned() {
344 self.stack.push(top);
345 }
346 }
347 JvmInstruction::DupX1 => {
348 self.validate_stack_size(2);
349 let top = self.stack.pop().unwrap();
350 let second = self.stack.pop().unwrap();
351 self.stack.push(top.clone());
352 self.stack.push(second);
353 self.stack.push(top);
354 }
355 JvmInstruction::DupX2 => {
356 self.validate_stack_size(3);
357 let top = self.stack.pop().unwrap();
358 let second = self.stack.pop().unwrap();
359 let third = self.stack.pop().unwrap();
360 self.stack.push(top.clone());
361 self.stack.push(third);
362 self.stack.push(second);
363 self.stack.push(top);
364 }
365 JvmInstruction::Dup2 => {
366 self.validate_stack_size(2);
367 let top = self.stack.pop().unwrap();
368 let second = self.stack.pop().unwrap();
369 self.stack.push(second.clone());
370 self.stack.push(top.clone());
371 self.stack.push(second);
372 self.stack.push(top);
373 }
374 JvmInstruction::Dup2X1 => {
375 self.validate_stack_size(3);
376 let top = self.stack.pop().unwrap();
377 let second = self.stack.pop().unwrap();
378 let third = self.stack.pop().unwrap();
379 self.stack.push(second.clone());
380 self.stack.push(top.clone());
381 self.stack.push(third);
382 self.stack.push(second);
383 self.stack.push(top);
384 }
385 JvmInstruction::Dup2X2 => {
386 self.validate_stack_size(4);
387 let top = self.stack.pop().unwrap();
388 let second = self.stack.pop().unwrap();
389 let third = self.stack.pop().unwrap();
390 let fourth = self.stack.pop().unwrap();
391 self.stack.push(second.clone());
392 self.stack.push(top.clone());
393 self.stack.push(fourth);
394 self.stack.push(third);
395 self.stack.push(second);
396 self.stack.push(top);
397 }
398 JvmInstruction::Swap => {
399 self.validate_stack_size(2);
400 let top = self.stack.pop().unwrap();
401 let second = self.stack.pop().unwrap();
402 self.stack.push(top);
403 self.stack.push(second);
404 }
405 JvmInstruction::Iadd | JvmInstruction::Isub | JvmInstruction::Imul |
406 JvmInstruction::Idiv | JvmInstruction::Irem | JvmInstruction::Ineg |
407 JvmInstruction::Ishl | JvmInstruction::Ishr | JvmInstruction::Iushr |
408 JvmInstruction::Iand | JvmInstruction::Ior | JvmInstruction::Ixor => {
409 let required = if matches!(instruction, JvmInstruction::Ineg) { 1 } else { 2 };
411 self.validate_stack_size(required);
412 for _ in 0..required {
413 self.stack.pop();
414 }
415 self.stack.push(JvmVerificationType::Integer);
416 }
417 JvmInstruction::Ladd | JvmInstruction::Lsub | JvmInstruction::Lmul |
418 JvmInstruction::Ldiv | JvmInstruction::Lrem | JvmInstruction::Lneg |
419 JvmInstruction::Lshl | JvmInstruction::Lshr | JvmInstruction::Lushr |
420 JvmInstruction::Land | JvmInstruction::Lor | JvmInstruction::Lxor => {
421 let required = if matches!(instruction, JvmInstruction::Lneg) { 1 } else { 2 };
423 self.validate_stack_size(required);
424 for _ in 0..required {
425 self.stack.pop();
426 }
427 self.stack.push(JvmVerificationType::Long);
428 }
429 JvmInstruction::Fadd | JvmInstruction::Fsub | JvmInstruction::Fmul |
430 JvmInstruction::Fdiv | JvmInstruction::Frem | JvmInstruction::Fneg => {
431 let required = if matches!(instruction, JvmInstruction::Fneg) { 1 } else { 2 };
433 self.validate_stack_size(required);
434 for _ in 0..required {
435 self.stack.pop();
436 }
437 self.stack.push(JvmVerificationType::Float);
438 }
439 JvmInstruction::Dadd | JvmInstruction::Dsub | JvmInstruction::Dmul |
440 JvmInstruction::Ddiv | JvmInstruction::Drem | JvmInstruction::Dneg => {
441 let required = if matches!(instruction, JvmInstruction::Dneg) { 1 } else { 2 };
443 self.validate_stack_size(required);
444 for _ in 0..required {
445 self.stack.pop();
446 }
447 self.stack.push(JvmVerificationType::Double);
448 }
449 JvmInstruction::Iinc { index, .. } => {
450 if *index as usize >= self.locals.len() {
452 self.errors.push(ValidationError::new(
453 "Local variable index out of bounds".to_string(),
454 self.current_index,
455 Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
456 ));
457 }
458 }
459 JvmInstruction::I2l => {
460 self.validate_stack_size(1);
461 self.stack.pop();
462 self.stack.push(JvmVerificationType::Long);
463 }
464 JvmInstruction::I2f => {
465 self.validate_stack_size(1);
466 self.stack.pop();
467 self.stack.push(JvmVerificationType::Float);
468 }
469 JvmInstruction::I2d => {
470 self.validate_stack_size(1);
471 self.stack.pop();
472 self.stack.push(JvmVerificationType::Double);
473 }
474 JvmInstruction::L2i => {
475 self.validate_stack_size(1);
476 self.stack.pop();
477 self.stack.push(JvmVerificationType::Integer);
478 }
479 JvmInstruction::L2f => {
480 self.validate_stack_size(1);
481 self.stack.pop();
482 self.stack.push(JvmVerificationType::Float);
483 }
484 JvmInstruction::L2d => {
485 self.validate_stack_size(1);
486 self.stack.pop();
487 self.stack.push(JvmVerificationType::Double);
488 }
489 JvmInstruction::F2i => {
490 self.validate_stack_size(1);
491 self.stack.pop();
492 self.stack.push(JvmVerificationType::Integer);
493 }
494 JvmInstruction::F2l => {
495 self.validate_stack_size(1);
496 self.stack.pop();
497 self.stack.push(JvmVerificationType::Long);
498 }
499 JvmInstruction::F2d => {
500 self.validate_stack_size(1);
501 self.stack.pop();
502 self.stack.push(JvmVerificationType::Double);
503 }
504 JvmInstruction::D2i => {
505 self.validate_stack_size(1);
506 self.stack.pop();
507 self.stack.push(JvmVerificationType::Integer);
508 }
509 JvmInstruction::D2l => {
510 self.validate_stack_size(1);
511 self.stack.pop();
512 self.stack.push(JvmVerificationType::Long);
513 }
514 JvmInstruction::D2f => {
515 self.validate_stack_size(1);
516 self.stack.pop();
517 self.stack.push(JvmVerificationType::Float);
518 }
519 JvmInstruction::I2b | JvmInstruction::I2c | JvmInstruction::I2s => {
520 self.validate_stack_size(1);
521 self.stack.pop();
522 self.stack.push(JvmVerificationType::Integer);
523 }
524 JvmInstruction::Lcmp => {
525 self.validate_stack_size(2);
526 self.stack.pop();
527 self.stack.pop();
528 self.stack.push(JvmVerificationType::Integer);
529 }
530 JvmInstruction::Fcmpl | JvmInstruction::Fcmpg => {
531 self.validate_stack_size(2);
532 self.stack.pop();
533 self.stack.pop();
534 self.stack.push(JvmVerificationType::Integer);
535 }
536 JvmInstruction::Dcmpl | JvmInstruction::Dcmpg => {
537 self.validate_stack_size(2);
538 self.stack.pop();
539 self.stack.pop();
540 self.stack.push(JvmVerificationType::Integer);
541 }
542 JvmInstruction::Ifeq { .. } | JvmInstruction::Ifne { .. } |
543 JvmInstruction::Iflt { .. } | JvmInstruction::Ifge { .. } |
544 JvmInstruction::Ifgt { .. } | JvmInstruction::Ifle { .. } => {
545 self.validate_stack_size(1);
547 self.stack.pop();
548 }
549 JvmInstruction::IfIcmpeq { .. } | JvmInstruction::IfIcmpne { .. } |
550 JvmInstruction::IfIcmplt { .. } | JvmInstruction::IfIcmpge { .. } |
551 JvmInstruction::IfIcmpgt { .. } | JvmInstruction::IfIcmple { .. } => {
552 self.validate_stack_size(2);
554 self.stack.pop();
555 self.stack.pop();
556 }
557 JvmInstruction::IfAcmpeq { .. } | JvmInstruction::IfAcmpne { .. } => {
558 self.validate_stack_size(2);
560 self.stack.pop();
561 self.stack.pop();
562 }
563 JvmInstruction::Goto { .. } | JvmInstruction::Jsr { .. } |
564 JvmInstruction::GotoW { .. } | JvmInstruction::JsrW { .. } => {
565 }
567 JvmInstruction::Tableswitch { .. } | JvmInstruction::Lookupswitch { .. } => {
568 self.validate_stack_size(1);
570 self.stack.pop();
571 }
572 JvmInstruction::Ireturn => {
573 self.validate_stack_size(1);
575 self.stack.pop();
576 }
577 JvmInstruction::Lreturn => {
578 self.validate_stack_size(1);
580 self.stack.pop();
581 }
582 JvmInstruction::Freturn => {
583 self.validate_stack_size(1);
585 self.stack.pop();
586 }
587 JvmInstruction::Dreturn => {
588 self.validate_stack_size(1);
590 self.stack.pop();
591 }
592 JvmInstruction::Areturn => {
593 self.validate_stack_size(1);
595 self.stack.pop();
596 }
597 JvmInstruction::Return => {
598 if !self.stack.is_empty() {
600 self.errors.push(ValidationError::new(
601 "Stack not empty on void return".to_string(),
602 self.current_index,
603 Some(format!("Stack size: {}", self.stack.len())),
604 ));
605 }
606 }
607 JvmInstruction::Getstatic { .. } => {
608 self.stack.push(JvmVerificationType::Integer);
611 }
612 JvmInstruction::Putstatic { .. } => {
613 self.validate_stack_size(1);
615 self.stack.pop();
616 }
617 JvmInstruction::Getfield { .. } => {
618 self.validate_stack_size(1);
620 self.stack.pop();
621 self.stack.push(JvmVerificationType::Integer);
622 }
623 JvmInstruction::Putfield { .. } => {
624 self.validate_stack_size(2);
626 self.stack.pop();
627 self.stack.pop();
628 }
629 JvmInstruction::Invokevirtual { .. } | JvmInstruction::Invokespecial { .. } |
630 JvmInstruction::Invokestatic { .. } | JvmInstruction::Invokeinterface { .. } |
631 JvmInstruction::Invokedynamic { .. } => {
632 self.validate_stack_size(1); self.stack.pop();
636 }
637 JvmInstruction::New { .. } => {
638 self.stack.push(JvmVerificationType::UninitializedThis);
640 }
641 JvmInstruction::Newarray { .. } => {
642 self.validate_stack_size(1);
644 self.stack.pop();
645 self.stack.push(JvmVerificationType::Object { class_name: "[I".to_string() });
646 }
647 JvmInstruction::Anewarray { .. } => {
648 self.validate_stack_size(1);
650 self.stack.pop();
651 self.stack.push(JvmVerificationType::Object { class_name: "[Ljava/lang/Object;".to_string() });
652 }
653 JvmInstruction::Arraylength => {
654 self.validate_stack_size(1);
656 self.stack.pop();
657 self.stack.push(JvmVerificationType::Integer);
658 }
659 JvmInstruction::Athrow => {
660 self.validate_stack_size(1);
662 self.stack.pop();
663 }
664 JvmInstruction::Checkcast { .. } => {
665 self.validate_stack_size(1);
667 self.stack.pop();
668 self.stack.push(JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
669 }
670 JvmInstruction::Instanceof { .. } => {
671 self.validate_stack_size(1);
673 self.stack.pop();
674 self.stack.push(JvmVerificationType::Integer);
675 }
676 JvmInstruction::Monitorenter | JvmInstruction::Monitorexit => {
677 self.validate_stack_size(1);
679 self.stack.pop();
680 }
681 JvmInstruction::Wide => {
682 }
684 JvmInstruction::Multianewarray { .. } => {
685 self.validate_stack_size(1);
687 self.stack.pop();
688 self.stack.push(JvmVerificationType::Object { class_name: "[[I".to_string() });
689 }
690 JvmInstruction::Ifnull { .. } | JvmInstruction::Ifnonnull { .. } => {
691 self.validate_stack_size(1);
693 self.stack.pop();
694 }
695 JvmInstruction::Ret { index } => {
696 if *index as usize >= self.locals.len() {
698 self.errors.push(ValidationError::new(
699 "Local variable index out of bounds".to_string(),
700 self.current_index,
701 Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
702 ));
703 }
704 }
705 JvmInstruction::Label { .. } => {
706 }
708 }
709
710 if self.stack.len() > self.method.max_stack as usize {
712 self.errors.push(ValidationError::new(
713 "Stack overflow".to_string(),
714 self.current_index,
715 Some(format!("Stack size {} exceeds max_stack {}", self.stack.len(), self.method.max_stack)),
716 ));
717 }
718 }
719
720 fn validate_load_instruction(&mut self, index: u16, expected_type: JvmVerificationType) {
722 let index_usize = index as usize;
723 if index_usize >= self.locals.len() {
724 self.errors.push(ValidationError::new(
725 "Local variable index out of bounds".to_string(),
726 self.current_index,
727 Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
728 ));
729 } else if self.locals[index_usize].is_none() {
730 self.errors.push(ValidationError::new(
731 "Uninitialized local variable access".to_string(),
732 self.current_index,
733 Some(format!("Variable at index {} is not initialized", index)),
734 ));
735 } else {
736 self.stack.push(expected_type);
738 }
739 }
740
741 fn validate_store_instruction(&mut self, index: u16, expected_type: JvmVerificationType) {
743 let index_usize = index as usize;
744 if index_usize >= self.locals.len() {
745 self.errors.push(ValidationError::new(
746 "Local variable index out of bounds".to_string(),
747 self.current_index,
748 Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
749 ));
750 } else if self.stack.is_empty() {
751 self.errors.push(ValidationError::new(
752 "Stack underflow on store instruction".to_string(),
753 self.current_index,
754 None,
755 ));
756 } else {
757 self.stack.pop();
759 self.locals[index_usize] = Some(expected_type);
760 }
761 }
762
763 fn validate_stack_size(&mut self, required: usize) {
765 if self.stack.len() < required {
766 self.errors.push(ValidationError::new(
767 "Stack underflow".to_string(),
768 self.current_index,
769 Some(format!("Required stack size: {}, actual: {}", required, self.stack.len())),
770 ));
771 }
772 }
773
774 fn check_return_instruction(&mut self) {
776 if let Some(last_inst) = self.method.instructions.last() {
777 match last_inst {
778 JvmInstruction::Ireturn | JvmInstruction::Lreturn | JvmInstruction::Freturn |
779 JvmInstruction::Dreturn | JvmInstruction::Areturn | JvmInstruction::Return => {
780 }
782 _ => {
783 self.errors.push(ValidationError::new(
784 "Method does not end with return instruction".to_string(),
785 self.method.instructions.len() - 1,
786 None,
787 ));
788 }
789 }
790 } else {
791 self.errors.push(ValidationError::new(
792 "Method has no instructions".to_string(),
793 0,
794 None,
795 ));
796 }
797 }
798}
799
800pub fn validate_program(program: &JvmProgram) -> Vec<ValidationError> {
802 let mut all_errors = Vec::new();
803
804 for (_method_index, method) in program.methods.iter().enumerate() {
805 let mut validator = BytecodeValidator::new(method);
806 let method_errors = validator.validate();
807
808 for error in method_errors {
810 all_errors.push(ValidationError::new(
811 format!("Method '{}': {}", method.name, error.message),
812 error.instruction_index,
813 error.detail,
814 ));
815 }
816 }
817
818 all_errors
819}