(context: &ControlFlowVerifier, labels: &[Label])
| 185 | } |
| 186 | |
| 187 | fn check_no_loop_splits(context: &ControlFlowVerifier, labels: &[Label]) -> PartialVMResult<()> { |
| 188 | let is_break = |loop_stack: &Vec<(CodeOffset, CodeOffset)>, jump_target: CodeOffset| -> bool { |
| 189 | match loop_stack.last() { |
| 190 | None => false, |
| 191 | Some((_cur_loop_head, last_continue)) => jump_target > *last_continue, |
| 192 | } |
| 193 | }; |
| 194 | let loop_depth = count_loop_depth(labels); |
| 195 | check_code(context, labels, |loop_stack, i, instr| { |
| 196 | match instr { |
| 197 | // Forward jump/"break" |
| 198 | Bytecode::Branch(j) | Bytecode::BrTrue(j) | Bytecode::BrFalse(j) |
| 199 | if *j > i && !is_break(loop_stack, *j) => |
| 200 | { |
| 201 | let j = *j; |
| 202 | let before_depth = loop_depth[i as usize]; |
| 203 | let after_depth = match &labels[j as usize] { |
| 204 | Label::Loop { .. } => loop_depth[j as usize] - 1, |
| 205 | Label::Code => loop_depth[j as usize], |
| 206 | }; |
| 207 | if before_depth != after_depth { |
| 208 | // Invalid forward jump. Entered the middle of a loop |
| 209 | Err(context.error(StatusCode::INVALID_LOOP_SPLIT, i)) |
| 210 | } else { |
| 211 | Ok(()) |
| 212 | } |
| 213 | } |
| 214 | _ => Ok(()), |
| 215 | } |
| 216 | }) |
| 217 | } |
| 218 | |
| 219 | // Only called after continues are verified, so we can assume that loops are well nested |
| 220 | fn count_loop_depth(labels: &[Label]) -> Vec<usize> { |
no test coverage detected