1#![forbid(unsafe_code)]
98
99use std::error::Error;
100use std::fmt;
101use std::marker::PhantomData;
102
103pub const MAGIC: [u8; 8] = [66, 77, 84, 66, 67, 0, 0, 1];
105pub const FORMAT_VERSION: u8 = 3;
107
108pub const MAX_REGISTERS: u32 = 1 << 16;
111pub const MAX_INSTRUCTIONS: u32 = 1 << 20;
113pub const MAX_HANDLERS: u32 = 1 << 16;
115pub const MAX_CONSTANTS: u32 = 1 << 20;
117pub const MAX_FUNCTIONS: u32 = 1 << 20;
119
120pub const MAX_VERIFIER_FACTS_WORDS: u64 = 1 << 23;
129
130const CANONICAL_NAN_BITS: u64 = 0x7ff8_0000_0000_0000;
131const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000;
132const FRACTION_MASK: u64 = 0x000f_ffff_ffff_ffff;
133
134macro_rules! index_type {
135 ($(#[$meta:meta])* $name:ident) => {
136 $(#[$meta])*
137 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
138 #[repr(transparent)]
139 pub struct $name(u32);
140
141 impl $name {
142 #[must_use]
143 pub const fn new(raw: u32) -> Self {
144 Self(raw)
145 }
146
147 #[must_use]
148 pub const fn get(self) -> u32 {
149 self.0
150 }
151 }
152 };
153}
154
155index_type!(
156 Register
158);
159index_type!(
160 ConstantId
162);
163index_type!(
164 FunctionId
166);
167index_type!(
168 Pc
170);
171
172mod string;
173
174mod program;
175
176pub use string::{EcmaString, EcmaStringBuilder, IllFormedUtf16, InvalidCodePoint};
177
178pub use program::{
179 Binding, BindingId, BindingKind, Edge, EdgeId, EdgeKind, EdgeTarget, Export, ExportSource,
180 ModuleId, PROGRAM_MAGIC, PROGRAM_VERSION, Program, ProgramDecodeError, ProgramDecodeErrorKind,
181 ProgramDecodeLimits, ProgramLoadError, ProgramModule, ProgramVerifyError,
182 ProgramVerifyErrorKind, ResolvedExport, decode_program, decode_verified_program,
183};
184
185#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
188#[repr(transparent)]
189pub struct NumberBits(u64);
190
191impl NumberBits {
192 #[must_use]
193 pub const fn from_bits(bits: u64) -> Self {
194 if is_nan(bits) {
195 Self(CANONICAL_NAN_BITS)
196 } else {
197 Self(bits)
198 }
199 }
200
201 #[must_use]
202 pub const fn from_f64(value: f64) -> Self {
203 Self::from_bits(value.to_bits())
204 }
205
206 #[must_use]
207 pub const fn bits(self) -> u64 {
208 self.0
209 }
210
211 #[must_use]
212 pub const fn to_f64(self) -> f64 {
213 f64::from_bits(self.0)
214 }
215
216 const fn from_wire(bits: u64) -> Option<Self> {
217 if is_nan(bits) && bits != CANONICAL_NAN_BITS {
218 None
219 } else {
220 Some(Self(bits))
221 }
222 }
223}
224
225const fn is_nan(bits: u64) -> bool {
226 bits & EXPONENT_MASK == EXPONENT_MASK && bits & FRACTION_MASK != 0
227}
228
229#[derive(Clone, Debug, Eq, Hash, PartialEq)]
233pub struct BigIntLiteral(String);
234
235impl BigIntLiteral {
236 #[must_use]
239 pub fn new(text: String) -> Option<Self> {
240 if is_canonical_bigint(&text) {
241 Some(Self(text))
242 } else {
243 None
244 }
245 }
246
247 #[must_use]
248 pub fn as_str(&self) -> &str {
249 &self.0
250 }
251}
252
253fn is_canonical_bigint(text: &str) -> bool {
254 let bytes = text.as_bytes();
255 if bytes.is_empty() {
256 return false;
257 }
258 let negative = bytes[0] == b'-';
259 let digits = if negative { &bytes[1..] } else { bytes };
260 if digits.is_empty() || !digits.iter().all(u8::is_ascii_digit) {
261 return false;
262 }
263 if digits.len() > 1 && digits[0] == b'0' {
265 return false;
266 }
267 !(negative && digits == b"0")
269}
270
271#[derive(Clone, Debug, Eq, PartialEq)]
276pub enum Constant {
277 Number(NumberBits),
278 Int32(i32),
279 String(EcmaString),
280 Boolean(bool),
281 Null,
282 Undefined,
283 BigInt(BigIntLiteral),
284}
285
286#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
288pub enum UnaryOp {
289 Void,
290 TypeOf,
291 Plus,
292 Negate,
293 BitwiseNot,
294 LogicalNot,
295}
296
297impl UnaryOp {
298 const fn to_u8(self) -> u8 {
299 match self {
300 Self::Void => 0,
301 Self::TypeOf => 1,
302 Self::Plus => 2,
303 Self::Negate => 3,
304 Self::BitwiseNot => 4,
305 Self::LogicalNot => 5,
306 }
307 }
308
309 const fn from_u8(tag: u8) -> Option<Self> {
310 match tag {
311 0 => Some(Self::Void),
312 1 => Some(Self::TypeOf),
313 2 => Some(Self::Plus),
314 3 => Some(Self::Negate),
315 4 => Some(Self::BitwiseNot),
316 5 => Some(Self::LogicalNot),
317 _ => None,
318 }
319 }
320}
321
322#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
324pub enum BinaryOp {
325 Add,
326 Subtract,
327 Multiply,
328 Divide,
329 Remainder,
330 Exponent,
331 BitAnd,
332 BitOr,
333 BitXor,
334 ShiftLeft,
335 ShiftRight,
336 UnsignedShiftRight,
337 Equal,
338 NotEqual,
339 StrictEqual,
340 StrictNotEqual,
341 LessThan,
342 LessThanOrEqual,
343 GreaterThan,
344 GreaterThanOrEqual,
345 InstanceOf,
346 In,
347}
348
349impl BinaryOp {
350 const fn to_u8(self) -> u8 {
351 match self {
352 Self::Add => 0,
353 Self::Subtract => 1,
354 Self::Multiply => 2,
355 Self::Divide => 3,
356 Self::Remainder => 4,
357 Self::Exponent => 5,
358 Self::BitAnd => 6,
359 Self::BitOr => 7,
360 Self::BitXor => 8,
361 Self::ShiftLeft => 9,
362 Self::ShiftRight => 10,
363 Self::UnsignedShiftRight => 11,
364 Self::Equal => 12,
365 Self::NotEqual => 13,
366 Self::StrictEqual => 14,
367 Self::StrictNotEqual => 15,
368 Self::LessThan => 16,
369 Self::LessThanOrEqual => 17,
370 Self::GreaterThan => 18,
371 Self::GreaterThanOrEqual => 19,
372 Self::InstanceOf => 20,
373 Self::In => 21,
374 }
375 }
376
377 const fn from_u8(tag: u8) -> Option<Self> {
378 match tag {
379 0 => Some(Self::Add),
380 1 => Some(Self::Subtract),
381 2 => Some(Self::Multiply),
382 3 => Some(Self::Divide),
383 4 => Some(Self::Remainder),
384 5 => Some(Self::Exponent),
385 6 => Some(Self::BitAnd),
386 7 => Some(Self::BitOr),
387 8 => Some(Self::BitXor),
388 9 => Some(Self::ShiftLeft),
389 10 => Some(Self::ShiftRight),
390 11 => Some(Self::UnsignedShiftRight),
391 12 => Some(Self::Equal),
392 13 => Some(Self::NotEqual),
393 14 => Some(Self::StrictEqual),
394 15 => Some(Self::StrictNotEqual),
395 16 => Some(Self::LessThan),
396 17 => Some(Self::LessThanOrEqual),
397 18 => Some(Self::GreaterThan),
398 19 => Some(Self::GreaterThanOrEqual),
399 20 => Some(Self::InstanceOf),
400 21 => Some(Self::In),
401 _ => None,
402 }
403 }
404}
405
406#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
408pub enum IteratorKind {
409 Sync,
411 Async,
413 Keys,
415}
416
417impl IteratorKind {
418 const fn to_u8(self) -> u8 {
419 match self {
420 Self::Sync => 0,
421 Self::Async => 1,
422 Self::Keys => 2,
423 }
424 }
425
426 const fn from_u8(tag: u8) -> Option<Self> {
427 match tag {
428 0 => Some(Self::Sync),
429 1 => Some(Self::Async),
430 2 => Some(Self::Keys),
431 _ => None,
432 }
433 }
434}
435
436#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
440pub enum AccessorKind {
441 Getter,
442 Setter,
443}
444
445impl AccessorKind {
446 const fn to_u8(self) -> u8 {
447 match self {
448 Self::Getter => 0,
449 Self::Setter => 1,
450 }
451 }
452
453 const fn from_u8(tag: u8) -> Option<Self> {
454 match tag {
455 0 => Some(Self::Getter),
456 1 => Some(Self::Setter),
457 _ => None,
458 }
459 }
460}
461
462#[derive(Clone, Copy, Debug, Eq, PartialEq)]
464pub enum Instruction {
465 LoadConst { dst: Register, constant: ConstantId },
467 Move { dst: Register, src: Register },
469 Unary {
471 dst: Register,
472 op: UnaryOp,
473 operand: Register,
474 },
475 Binary {
477 dst: Register,
478 op: BinaryOp,
479 left: Register,
480 right: Register,
481 },
482 CreateObject { dst: Register },
484 CreateArray { dst: Register },
486 CreateCell { dst: Register },
489 CreateClosure {
493 dst: Register,
494 function: FunctionId,
495 captures: Register,
496 },
497 GetProperty {
499 dst: Register,
500 object: Register,
501 key: Register,
502 },
503 SetProperty {
505 object: Register,
506 key: Register,
507 value: Register,
508 },
509 DeleteProperty {
511 dst: Register,
512 object: Register,
513 key: Register,
514 },
515 DefineAccessor {
517 object: Register,
518 key: Register,
519 accessor: Register,
520 kind: AccessorKind,
521 },
522 Call {
526 dst: Register,
527 callee: Register,
528 this_value: Register,
529 arguments: Register,
530 },
531 Construct {
534 dst: Register,
535 callee: Register,
536 arguments: Register,
537 },
538 LoadGlobal { dst: Register, name: ConstantId },
541 StoreGlobal { name: ConstantId, value: Register },
543 TypeOfGlobal { dst: Register, name: ConstantId },
546 LoadThis { dst: Register },
548 LoadArguments { dst: Register },
550 LoadNewTarget { dst: Register },
552 ArrayPush { array: Register, value: Register },
554 ArrayExtend { array: Register, iterable: Register },
556 ObjectSpread { target: Register, source: Register },
559 SetPrototype {
561 object: Register,
562 prototype: Register,
563 },
564 CreatePrivateName {
568 dst: Register,
569 description: ConstantId,
570 },
571 CreateRegExp {
573 dst: Register,
574 pattern: ConstantId,
575 flags: ConstantId,
576 },
577 GetIterator {
579 dst: Register,
580 src: Register,
581 kind: IteratorKind,
582 },
583 IteratorNext {
586 done: Register,
587 value: Register,
588 iterator: Register,
589 },
590 Jump { target: Pc },
592 JumpIfTrue { condition: Register, target: Pc },
594 JumpIfFalse { condition: Register, target: Pc },
596 Return { value: Register },
598 Throw { value: Register },
600 Suspend {
603 dst: Register,
604 src: Register,
605 resume: Pc,
606 },
607 Import {
609 dst: Register,
610 specifier: ConstantId,
611 },
612 Export { name: ConstantId, src: Register },
614 Halt,
616}
617
618impl Instruction {
619 fn visit_reads(self, mut visit: impl FnMut(Register)) {
621 match self {
622 Self::Move { src, .. } => visit(src),
623 Self::Unary { operand, .. } => visit(operand),
624 Self::Binary { left, right, .. } => {
625 visit(left);
626 visit(right);
627 }
628 Self::CreateClosure { captures, .. } => visit(captures),
629 Self::GetProperty { object, key, .. } | Self::DeleteProperty { object, key, .. } => {
630 visit(object);
631 visit(key);
632 }
633 Self::SetProperty { object, key, value } => {
634 visit(object);
635 visit(key);
636 visit(value);
637 }
638 Self::DefineAccessor {
639 object,
640 key,
641 accessor,
642 ..
643 } => {
644 visit(object);
645 visit(key);
646 visit(accessor);
647 }
648 Self::Call {
649 callee,
650 this_value,
651 arguments,
652 ..
653 } => {
654 visit(callee);
655 visit(this_value);
656 visit(arguments);
657 }
658 Self::Construct {
659 callee, arguments, ..
660 } => {
661 visit(callee);
662 visit(arguments);
663 }
664 Self::StoreGlobal { value, .. } => visit(value),
665 Self::ArrayPush { array, value } => {
666 visit(array);
667 visit(value);
668 }
669 Self::ArrayExtend { array, iterable } => {
670 visit(array);
671 visit(iterable);
672 }
673 Self::ObjectSpread { target, source } => {
674 visit(target);
675 visit(source);
676 }
677 Self::SetPrototype { object, prototype } => {
678 visit(object);
679 visit(prototype);
680 }
681 Self::GetIterator { src, .. } => visit(src),
682 Self::IteratorNext { iterator, .. } => visit(iterator),
683 Self::JumpIfTrue { condition, .. } | Self::JumpIfFalse { condition, .. } => {
684 visit(condition);
685 }
686 Self::Return { value } | Self::Throw { value } | Self::Export { src: value, .. } => {
687 visit(value);
688 }
689 Self::Suspend { src, .. } => visit(src),
690 Self::LoadConst { .. }
691 | Self::CreateObject { .. }
692 | Self::CreateArray { .. }
693 | Self::CreateCell { .. }
694 | Self::LoadGlobal { .. }
695 | Self::TypeOfGlobal { .. }
696 | Self::LoadThis { .. }
697 | Self::LoadArguments { .. }
698 | Self::LoadNewTarget { .. }
699 | Self::CreatePrivateName { .. }
700 | Self::CreateRegExp { .. }
701 | Self::Jump { .. }
702 | Self::Import { .. }
703 | Self::Halt => {}
704 }
705 }
706
707 fn visit_writes(self, mut visit: impl FnMut(Register)) {
710 match self {
711 Self::LoadConst { dst, .. }
712 | Self::Move { dst, .. }
713 | Self::Unary { dst, .. }
714 | Self::Binary { dst, .. }
715 | Self::CreateObject { dst }
716 | Self::CreateArray { dst }
717 | Self::CreateCell { dst }
718 | Self::CreateClosure { dst, .. }
719 | Self::GetProperty { dst, .. }
720 | Self::DeleteProperty { dst, .. }
721 | Self::Call { dst, .. }
722 | Self::Construct { dst, .. }
723 | Self::LoadGlobal { dst, .. }
724 | Self::TypeOfGlobal { dst, .. }
725 | Self::LoadThis { dst }
726 | Self::LoadArguments { dst }
727 | Self::LoadNewTarget { dst }
728 | Self::CreatePrivateName { dst, .. }
729 | Self::CreateRegExp { dst, .. }
730 | Self::GetIterator { dst, .. }
731 | Self::Suspend { dst, .. }
732 | Self::Import { dst, .. } => visit(dst),
733 Self::IteratorNext { done, value, .. } => {
734 visit(done);
735 visit(value);
736 }
737 Self::SetProperty { .. }
738 | Self::DefineAccessor { .. }
739 | Self::StoreGlobal { .. }
740 | Self::ArrayPush { .. }
741 | Self::ArrayExtend { .. }
742 | Self::ObjectSpread { .. }
743 | Self::SetPrototype { .. }
744 | Self::Export { .. }
745 | Self::Jump { .. }
746 | Self::JumpIfTrue { .. }
747 | Self::JumpIfFalse { .. }
748 | Self::Return { .. }
749 | Self::Throw { .. }
750 | Self::Halt => {}
751 }
752 }
753
754 fn visit_successors(self, pc: u32, mut visit: impl FnMut(Pc)) {
758 match self {
759 Self::Jump { target } => visit(target),
760 Self::JumpIfTrue { target, .. } | Self::JumpIfFalse { target, .. } => {
761 visit(target);
762 visit(Pc::new(pc + 1));
763 }
764 Self::Suspend { resume, .. } => visit(resume),
765 Self::Return { .. } | Self::Throw { .. } | Self::Halt => {}
766 Self::LoadConst { .. }
767 | Self::Move { .. }
768 | Self::Unary { .. }
769 | Self::Binary { .. }
770 | Self::CreateObject { .. }
771 | Self::CreateArray { .. }
772 | Self::CreateCell { .. }
773 | Self::CreateClosure { .. }
774 | Self::GetProperty { .. }
775 | Self::SetProperty { .. }
776 | Self::DeleteProperty { .. }
777 | Self::DefineAccessor { .. }
778 | Self::Call { .. }
779 | Self::Construct { .. }
780 | Self::LoadGlobal { .. }
781 | Self::StoreGlobal { .. }
782 | Self::TypeOfGlobal { .. }
783 | Self::LoadThis { .. }
784 | Self::LoadArguments { .. }
785 | Self::LoadNewTarget { .. }
786 | Self::ArrayPush { .. }
787 | Self::ArrayExtend { .. }
788 | Self::ObjectSpread { .. }
789 | Self::SetPrototype { .. }
790 | Self::CreatePrivateName { .. }
791 | Self::CreateRegExp { .. }
792 | Self::GetIterator { .. }
793 | Self::IteratorNext { .. }
794 | Self::Import { .. }
795 | Self::Export { .. } => visit(Pc::new(pc + 1)),
796 }
797 }
798}
799
800#[derive(Clone, Copy, Debug, Eq, PartialEq)]
803pub struct ExceptionHandler {
804 pub start: Pc,
805 pub end: Pc,
806 pub handler: Pc,
807 pub catch_register: Register,
808}
809
810#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
812pub struct FunctionFlags {
813 pub is_async: bool,
814 pub is_generator: bool,
815}
816
817impl FunctionFlags {
818 const ASYNC: u8 = 0b01;
819 const GENERATOR: u8 = 0b10;
820 const KNOWN: u8 = Self::ASYNC | Self::GENERATOR;
821
822 const fn to_bits(self) -> u8 {
823 let mut bits = 0;
824 if self.is_async {
825 bits |= Self::ASYNC;
826 }
827 if self.is_generator {
828 bits |= Self::GENERATOR;
829 }
830 bits
831 }
832
833 const fn from_bits(bits: u8) -> Option<Self> {
834 if bits & !Self::KNOWN != 0 {
835 return None;
836 }
837 Some(Self {
838 is_async: bits & Self::ASYNC != 0,
839 is_generator: bits & Self::GENERATOR != 0,
840 })
841 }
842}
843
844#[derive(Clone, Debug, Eq, PartialEq)]
849pub struct Function {
850 name: Option<ConstantId>,
851 capture_count: u32,
852 parameter_count: u32,
853 register_count: u32,
854 flags: FunctionFlags,
855 code: Vec<Instruction>,
856 handlers: Vec<ExceptionHandler>,
857}
858
859impl Function {
860 #[must_use]
861 pub fn new(
862 name: Option<ConstantId>,
863 capture_count: u32,
864 parameter_count: u32,
865 register_count: u32,
866 flags: FunctionFlags,
867 code: Vec<Instruction>,
868 handlers: Vec<ExceptionHandler>,
869 ) -> Self {
870 Self {
871 name,
872 capture_count,
873 parameter_count,
874 register_count,
875 flags,
876 code,
877 handlers,
878 }
879 }
880
881 #[must_use]
882 pub const fn name(&self) -> Option<ConstantId> {
883 self.name
884 }
885
886 #[must_use]
887 pub const fn capture_count(&self) -> u32 {
888 self.capture_count
889 }
890
891 #[must_use]
892 pub const fn parameter_count(&self) -> u32 {
893 self.parameter_count
894 }
895
896 #[must_use]
897 pub const fn register_count(&self) -> u32 {
898 self.register_count
899 }
900
901 #[must_use]
902 pub const fn flags(&self) -> FunctionFlags {
903 self.flags
904 }
905
906 #[must_use]
907 pub fn code(&self) -> &[Instruction] {
908 &self.code
909 }
910
911 #[must_use]
912 pub fn handlers(&self) -> &[ExceptionHandler] {
913 &self.handlers
914 }
915
916 const fn entry_initialized(&self) -> u32 {
920 self.capture_count.saturating_add(self.parameter_count)
921 }
922}
923
924#[derive(Clone, Copy, Debug, Eq, PartialEq)]
926pub struct Unverified {
927 _private: (),
928}
929
930#[derive(Clone, Copy, Debug, Eq, PartialEq)]
932pub struct Verified {
933 _private: (),
934}
935
936#[derive(Clone, Debug, Eq, PartialEq)]
938pub struct Module<State = Unverified> {
939 constants: Vec<Constant>,
940 functions: Vec<Function>,
941 entry: FunctionId,
942 certificates: Vec<Certificate>,
943 state: PhantomData<State>,
944}
945
946impl<State> Module<State> {
947 #[must_use]
948 pub fn constants(&self) -> &[Constant] {
949 &self.constants
950 }
951
952 #[must_use]
953 pub fn functions(&self) -> &[Function] {
954 &self.functions
955 }
956
957 #[must_use]
958 pub const fn entry(&self) -> FunctionId {
959 self.entry
960 }
961}
962
963impl Module<Unverified> {
964 #[must_use]
965 pub fn new(constants: Vec<Constant>, functions: Vec<Function>, entry: FunctionId) -> Self {
966 Self {
967 constants,
968 functions,
969 entry,
970 certificates: Vec::new(),
971 state: PhantomData,
972 }
973 }
974
975 pub fn verify(self) -> Result<Module<Verified>, VerifyError> {
981 verify_module(self)
982 }
983}
984
985impl Module<Verified> {
986 #[must_use]
987 pub fn certificate(&self, function: FunctionId) -> Option<&Certificate> {
988 self.certificates.get(function.get() as usize)
989 }
990
991 #[must_use]
993 pub fn verification_bytes(&self) -> usize {
994 self.certificates.iter().fold(0usize, |bytes, certificate| {
995 bytes.saturating_add(certificate.retained_bytes())
996 })
997 }
998
999 #[must_use]
1001 pub fn encode(&self) -> Vec<u8> {
1002 let mut output = Vec::new();
1003 output.extend_from_slice(&MAGIC);
1004 output.push(FORMAT_VERSION);
1005 write_u32(self.constants.len() as u32, &mut output);
1006 for constant in &self.constants {
1007 encode_constant(constant, &mut output);
1008 }
1009 write_u32(self.functions.len() as u32, &mut output);
1010 write_u32(self.entry.get(), &mut output);
1011 for function in &self.functions {
1012 encode_function(function, &mut output);
1013 }
1014 output
1015 }
1016}
1017
1018#[derive(Clone, Debug, Eq, PartialEq)]
1021pub struct Certificate {
1022 register_count: u32,
1023 facts: Vec<RegisterSet>,
1024}
1025
1026impl Certificate {
1027 fn retained_bytes(&self) -> usize {
1028 self.facts.iter().fold(
1029 std::mem::size_of::<Self>().saturating_add(
1030 self.facts
1031 .len()
1032 .saturating_mul(std::mem::size_of::<RegisterSet>()),
1033 ),
1034 |bytes, facts| {
1035 bytes.saturating_add(facts.words.len().saturating_mul(std::mem::size_of::<u64>()))
1036 },
1037 )
1038 }
1039
1040 #[must_use]
1041 pub fn instruction_count(&self) -> usize {
1042 self.facts.len()
1043 }
1044
1045 #[must_use]
1049 pub fn initialized_before(&self, pc: Pc, register: Register) -> Option<bool> {
1050 if register.get() >= self.register_count {
1051 return None;
1052 }
1053 self.facts
1054 .get(pc.get() as usize)
1055 .map(|facts| facts.contains(register))
1056 }
1057}
1058
1059#[derive(Clone, Debug, Eq, PartialEq)]
1061struct RegisterSet {
1062 words: Box<[u64]>,
1063}
1064
1065impl RegisterSet {
1066 fn words_for(register_count: u32) -> usize {
1067 (register_count as usize).div_ceil(64)
1068 }
1069
1070 fn empty(register_count: u32) -> Self {
1071 Self {
1072 words: vec![0; Self::words_for(register_count)].into_boxed_slice(),
1073 }
1074 }
1075
1076 fn full(register_count: u32) -> Self {
1077 let words_len = Self::words_for(register_count);
1078 let mut words = vec![u64::MAX; words_len];
1079 let remainder = register_count % 64;
1080 if remainder != 0 && words_len != 0 {
1081 words[words_len - 1] = (1_u64 << remainder) - 1;
1082 }
1083 Self {
1084 words: words.into_boxed_slice(),
1085 }
1086 }
1087
1088 fn contains(&self, register: Register) -> bool {
1089 let index = register.get() as usize;
1090 self.words
1091 .get(index / 64)
1092 .is_some_and(|word| word & (1_u64 << (index % 64)) != 0)
1093 }
1094
1095 fn insert(&mut self, register: Register) {
1096 let index = register.get() as usize;
1097 if let Some(word) = self.words.get_mut(index / 64) {
1098 *word |= 1_u64 << (index % 64);
1099 }
1100 }
1101
1102 fn insert_prefix(&mut self, count: u32) {
1103 for register in 0..count {
1104 self.insert(Register::new(register));
1105 }
1106 }
1107
1108 fn intersect(&mut self, other: &Self) -> bool {
1109 let mut changed = false;
1110 for (slot, mask) in self.words.iter_mut().zip(other.words.iter()) {
1111 let next = *slot & *mask;
1112 if next != *slot {
1113 changed = true;
1114 *slot = next;
1115 }
1116 }
1117 changed
1118 }
1119}
1120
1121#[derive(Clone, Debug, Eq, PartialEq)]
1123pub struct VerifyError {
1124 pub function: Option<FunctionId>,
1125 pub instruction: Option<Pc>,
1126 pub kind: VerifyErrorKind,
1127}
1128
1129#[derive(Clone, Debug, Eq, PartialEq)]
1130pub enum VerifyErrorKind {
1131 EmptyModule,
1132 VerifierWorkLimitExceeded {
1133 work: u64,
1134 limit: u64,
1135 },
1136 TooManyConstants {
1137 count: usize,
1138 },
1139 TooManyFunctions {
1140 count: usize,
1141 },
1142 EntryFunctionOutOfBounds {
1143 entry: u32,
1144 function_count: usize,
1145 },
1146 EmptyFunction,
1147 TooManyInstructions {
1148 count: usize,
1149 },
1150 TooManyHandlers {
1151 count: usize,
1152 },
1153 RegisterCountOutOfBounds {
1154 count: u32,
1155 },
1156 ParameterCountExceedsRegisters {
1157 parameter_count: u32,
1158 register_count: u32,
1159 },
1160 EntryRegistersExceedRegisterCount {
1161 capture_count: u32,
1162 parameter_count: u32,
1163 register_count: u32,
1164 },
1165 FunctionNameOutOfBounds {
1166 constant: u32,
1167 },
1168 FunctionNameNotString {
1169 constant: ConstantId,
1170 },
1171 RegisterOutOfBounds {
1172 register: Register,
1173 register_count: u32,
1174 },
1175 ConstantOutOfBounds {
1176 constant: ConstantId,
1177 constant_count: usize,
1178 },
1179 StringConstantExpected {
1180 constant: ConstantId,
1181 },
1182 FunctionReferenceOutOfBounds {
1183 function: FunctionId,
1184 function_count: usize,
1185 },
1186 JumpOutOfBounds {
1187 target: u32,
1188 instruction_count: usize,
1189 },
1190 InvalidHandlerBounds {
1191 handler: usize,
1192 start: u32,
1193 end: u32,
1194 target: u32,
1195 },
1196 HandlerCatchRegisterOutOfBounds {
1197 handler: usize,
1198 register: Register,
1199 register_count: u32,
1200 },
1201 HandlersPartiallyOverlap {
1202 left: usize,
1203 right: usize,
1204 },
1205 ReadBeforeWrite {
1206 register: Register,
1207 },
1208}
1209
1210impl fmt::Display for VerifyError {
1211 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1212 if let Some(function) = self.function {
1213 write!(formatter, "function {}", function.get())?;
1214 if let Some(instruction) = self.instruction {
1215 write!(formatter, " instruction {}", instruction.get())?;
1216 }
1217 formatter.write_str(": ")?;
1218 }
1219 match &self.kind {
1220 VerifyErrorKind::EmptyModule => formatter.write_str("module has no functions"),
1221 VerifyErrorKind::VerifierWorkLimitExceeded { work, limit } => write!(
1222 formatter,
1223 "verifier fact allocation {work} words exceeds the {limit}-word limit"
1224 ),
1225 VerifyErrorKind::TooManyConstants { count } => {
1226 write!(formatter, "{count} constants exceed the structural limit")
1227 }
1228 VerifyErrorKind::TooManyFunctions { count } => {
1229 write!(formatter, "{count} functions exceed the structural limit")
1230 }
1231 VerifyErrorKind::EntryFunctionOutOfBounds {
1232 entry,
1233 function_count,
1234 } => write!(
1235 formatter,
1236 "entry function {entry} is outside {function_count} functions"
1237 ),
1238 VerifyErrorKind::EmptyFunction => {
1239 formatter.write_str("function has no entry instruction")
1240 }
1241 VerifyErrorKind::TooManyInstructions { count } => {
1242 write!(
1243 formatter,
1244 "{count} instructions exceed the structural limit"
1245 )
1246 }
1247 VerifyErrorKind::TooManyHandlers { count } => {
1248 write!(formatter, "{count} handlers exceed the structural limit")
1249 }
1250 VerifyErrorKind::RegisterCountOutOfBounds { count } => {
1251 write!(
1252 formatter,
1253 "register count {count} exceeds the structural limit"
1254 )
1255 }
1256 VerifyErrorKind::ParameterCountExceedsRegisters {
1257 parameter_count,
1258 register_count,
1259 } => write!(
1260 formatter,
1261 "parameter count {parameter_count} exceeds register count {register_count}"
1262 ),
1263 VerifyErrorKind::EntryRegistersExceedRegisterCount {
1264 capture_count,
1265 parameter_count,
1266 register_count,
1267 } => write!(
1268 formatter,
1269 "capture count {capture_count} plus parameter count {parameter_count} exceeds \
1270 register count {register_count}"
1271 ),
1272 VerifyErrorKind::FunctionNameOutOfBounds { constant } => {
1273 write!(
1274 formatter,
1275 "function name constant {constant} is out of bounds"
1276 )
1277 }
1278 VerifyErrorKind::FunctionNameNotString { constant } => write!(
1279 formatter,
1280 "function name constant {} is not a string",
1281 constant.get()
1282 ),
1283 VerifyErrorKind::RegisterOutOfBounds {
1284 register,
1285 register_count,
1286 } => write!(
1287 formatter,
1288 "register {} is outside register count {register_count}",
1289 register.get()
1290 ),
1291 VerifyErrorKind::ConstantOutOfBounds {
1292 constant,
1293 constant_count,
1294 } => write!(
1295 formatter,
1296 "constant {} is outside {constant_count} constants",
1297 constant.get()
1298 ),
1299 VerifyErrorKind::StringConstantExpected { constant } => {
1300 write!(formatter, "constant {} must be a string", constant.get())
1301 }
1302 VerifyErrorKind::FunctionReferenceOutOfBounds {
1303 function,
1304 function_count,
1305 } => write!(
1306 formatter,
1307 "function reference {} is outside {function_count} functions",
1308 function.get()
1309 ),
1310 VerifyErrorKind::JumpOutOfBounds {
1311 target,
1312 instruction_count,
1313 } => write!(
1314 formatter,
1315 "target {target} is not one of {instruction_count} instruction boundaries"
1316 ),
1317 VerifyErrorKind::InvalidHandlerBounds {
1318 handler,
1319 start,
1320 end,
1321 target,
1322 } => write!(
1323 formatter,
1324 "handler {handler} has invalid range {start}..{end} or target {target}"
1325 ),
1326 VerifyErrorKind::HandlerCatchRegisterOutOfBounds {
1327 handler,
1328 register,
1329 register_count,
1330 } => write!(
1331 formatter,
1332 "handler {handler} catch register {} is outside register count {register_count}",
1333 register.get()
1334 ),
1335 VerifyErrorKind::HandlersPartiallyOverlap { left, right } => write!(
1336 formatter,
1337 "handlers {left} and {right} partially overlap instead of nesting"
1338 ),
1339 VerifyErrorKind::ReadBeforeWrite { register } => write!(
1340 formatter,
1341 "register {} may be read before initialization",
1342 register.get()
1343 ),
1344 }
1345 }
1346}
1347
1348impl Error for VerifyError {}
1349
1350fn module_error(kind: VerifyErrorKind) -> VerifyError {
1351 VerifyError {
1352 function: None,
1353 instruction: None,
1354 kind,
1355 }
1356}
1357
1358fn function_error(function: usize, kind: VerifyErrorKind) -> VerifyError {
1359 VerifyError {
1360 function: Some(FunctionId::new(function as u32)),
1361 instruction: None,
1362 kind,
1363 }
1364}
1365
1366fn instruction_error(function: usize, pc: usize, kind: VerifyErrorKind) -> VerifyError {
1367 VerifyError {
1368 function: Some(FunctionId::new(function as u32)),
1369 instruction: Some(Pc::new(pc as u32)),
1370 kind,
1371 }
1372}
1373
1374fn verify_module(module: Module<Unverified>) -> Result<Module<Verified>, VerifyError> {
1375 if module.functions.is_empty() {
1376 return Err(module_error(VerifyErrorKind::EmptyModule));
1377 }
1378 if module.constants.len() as u64 > u64::from(MAX_CONSTANTS) {
1379 return Err(module_error(VerifyErrorKind::TooManyConstants {
1380 count: module.constants.len(),
1381 }));
1382 }
1383 if module.functions.len() as u64 > u64::from(MAX_FUNCTIONS) {
1384 return Err(module_error(VerifyErrorKind::TooManyFunctions {
1385 count: module.functions.len(),
1386 }));
1387 }
1388 if module.entry.get() as usize >= module.functions.len() {
1389 return Err(module_error(VerifyErrorKind::EntryFunctionOutOfBounds {
1390 entry: module.entry.get(),
1391 function_count: module.functions.len(),
1392 }));
1393 }
1394
1395 let mut total_facts_words: u64 = 0;
1405 for function in &module.functions {
1406 let words = RegisterSet::words_for(function.register_count) as u64;
1407 let function_words = (function.code.len() as u64).saturating_mul(words);
1408 total_facts_words = total_facts_words.saturating_add(function_words);
1409 if total_facts_words > MAX_VERIFIER_FACTS_WORDS {
1410 return Err(module_error(VerifyErrorKind::VerifierWorkLimitExceeded {
1411 work: total_facts_words,
1412 limit: MAX_VERIFIER_FACTS_WORDS,
1413 }));
1414 }
1415 }
1416
1417 let mut certificates = Vec::with_capacity(module.functions.len());
1418 for (index, function) in module.functions.iter().enumerate() {
1419 certificates.push(verify_function(&module, index, function)?);
1420 }
1421
1422 Ok(Module {
1423 constants: module.constants,
1424 functions: module.functions,
1425 entry: module.entry,
1426 certificates,
1427 state: PhantomData,
1428 })
1429}
1430
1431fn verify_function(
1432 module: &Module<Unverified>,
1433 function_index: usize,
1434 function: &Function,
1435) -> Result<Certificate, VerifyError> {
1436 if function.code.is_empty() {
1437 return Err(function_error(
1438 function_index,
1439 VerifyErrorKind::EmptyFunction,
1440 ));
1441 }
1442 if function.code.len() as u64 > u64::from(MAX_INSTRUCTIONS) {
1443 return Err(function_error(
1444 function_index,
1445 VerifyErrorKind::TooManyInstructions {
1446 count: function.code.len(),
1447 },
1448 ));
1449 }
1450 if function.handlers.len() as u64 > u64::from(MAX_HANDLERS) {
1451 return Err(function_error(
1452 function_index,
1453 VerifyErrorKind::TooManyHandlers {
1454 count: function.handlers.len(),
1455 },
1456 ));
1457 }
1458 if function.register_count > MAX_REGISTERS {
1459 return Err(function_error(
1460 function_index,
1461 VerifyErrorKind::RegisterCountOutOfBounds {
1462 count: function.register_count,
1463 },
1464 ));
1465 }
1466 if function.parameter_count > function.register_count {
1467 return Err(function_error(
1468 function_index,
1469 VerifyErrorKind::ParameterCountExceedsRegisters {
1470 parameter_count: function.parameter_count,
1471 register_count: function.register_count,
1472 },
1473 ));
1474 }
1475 if u64::from(function.capture_count) + u64::from(function.parameter_count)
1478 > u64::from(function.register_count)
1479 {
1480 return Err(function_error(
1481 function_index,
1482 VerifyErrorKind::EntryRegistersExceedRegisterCount {
1483 capture_count: function.capture_count,
1484 parameter_count: function.parameter_count,
1485 register_count: function.register_count,
1486 },
1487 ));
1488 }
1489 verify_function_name(module, function_index, function)?;
1490 verify_handlers(function_index, function)?;
1491 for (pc, instruction) in function.code.iter().copied().enumerate() {
1492 verify_instruction(module, function_index, function, pc, instruction)?;
1493 }
1494 definite_initialization(function_index, function)
1495}
1496
1497fn verify_function_name(
1498 module: &Module<Unverified>,
1499 function_index: usize,
1500 function: &Function,
1501) -> Result<(), VerifyError> {
1502 let Some(name) = function.name else {
1503 return Ok(());
1504 };
1505 let Some(constant) = module.constants.get(name.get() as usize) else {
1506 return Err(function_error(
1507 function_index,
1508 VerifyErrorKind::FunctionNameOutOfBounds {
1509 constant: name.get(),
1510 },
1511 ));
1512 };
1513 if !matches!(constant, Constant::String(_)) {
1514 return Err(function_error(
1515 function_index,
1516 VerifyErrorKind::FunctionNameNotString { constant: name },
1517 ));
1518 }
1519 Ok(())
1520}
1521
1522fn verify_handlers(function_index: usize, function: &Function) -> Result<(), VerifyError> {
1523 let code_len = function.code.len();
1524 for (index, handler) in function.handlers.iter().copied().enumerate() {
1525 if handler.start.get() >= handler.end.get()
1526 || handler.end.get() as usize > code_len
1527 || handler.handler.get() as usize >= code_len
1528 {
1529 return Err(function_error(
1530 function_index,
1531 VerifyErrorKind::InvalidHandlerBounds {
1532 handler: index,
1533 start: handler.start.get(),
1534 end: handler.end.get(),
1535 target: handler.handler.get(),
1536 },
1537 ));
1538 }
1539 if handler.catch_register.get() >= function.register_count {
1540 return Err(function_error(
1541 function_index,
1542 VerifyErrorKind::HandlerCatchRegisterOutOfBounds {
1543 handler: index,
1544 register: handler.catch_register,
1545 register_count: function.register_count,
1546 },
1547 ));
1548 }
1549 }
1550 let mut order: Vec<usize> = (0..function.handlers.len()).collect();
1556 order.sort_by(|&left, &right| {
1557 let a = function.handlers[left];
1558 let b = function.handlers[right];
1559 a.start
1560 .get()
1561 .cmp(&b.start.get())
1562 .then_with(|| b.end.get().cmp(&a.end.get()))
1563 });
1564 let mut open: Vec<(u32, usize)> = Vec::new();
1565 for &index in &order {
1566 let range = function.handlers[index];
1567 let start = range.start.get();
1568 let end = range.end.get();
1569 while open.last().is_some_and(|&(open_end, _)| open_end <= start) {
1572 open.pop();
1573 }
1574 if let Some(&(parent_end, parent_index)) = open.last() {
1575 if end > parent_end {
1579 let (left, right) = if parent_index < index {
1580 (parent_index, index)
1581 } else {
1582 (index, parent_index)
1583 };
1584 return Err(function_error(
1585 function_index,
1586 VerifyErrorKind::HandlersPartiallyOverlap { left, right },
1587 ));
1588 }
1589 }
1590 open.push((end, index));
1591 }
1592 Ok(())
1593}
1594
1595fn verify_instruction(
1596 module: &Module<Unverified>,
1597 function_index: usize,
1598 function: &Function,
1599 pc: usize,
1600 instruction: Instruction,
1601) -> Result<(), VerifyError> {
1602 let register_count = function.register_count;
1603 let constant_count = module.constants.len();
1604 let function_count = module.functions.len();
1605 let code_len = function.code.len();
1606
1607 let check_register = |register: Register| -> Result<(), VerifyError> {
1608 if register.get() >= register_count {
1609 Err(instruction_error(
1610 function_index,
1611 pc,
1612 VerifyErrorKind::RegisterOutOfBounds {
1613 register,
1614 register_count,
1615 },
1616 ))
1617 } else {
1618 Ok(())
1619 }
1620 };
1621 let check_constant = |constant: ConstantId| -> Result<(), VerifyError> {
1622 if constant.get() as usize >= constant_count {
1623 Err(instruction_error(
1624 function_index,
1625 pc,
1626 VerifyErrorKind::ConstantOutOfBounds {
1627 constant,
1628 constant_count,
1629 },
1630 ))
1631 } else {
1632 Ok(())
1633 }
1634 };
1635 let check_string_constant = |constant: ConstantId| -> Result<(), VerifyError> {
1638 check_constant(constant)?;
1639 if matches!(
1640 module.constants[constant.get() as usize],
1641 Constant::String(_)
1642 ) {
1643 Ok(())
1644 } else {
1645 Err(instruction_error(
1646 function_index,
1647 pc,
1648 VerifyErrorKind::StringConstantExpected { constant },
1649 ))
1650 }
1651 };
1652
1653 match instruction {
1654 Instruction::LoadConst { dst, constant } => {
1655 check_register(dst)?;
1656 check_constant(constant)?;
1657 }
1658 Instruction::Move { dst, src } => {
1659 check_register(dst)?;
1660 check_register(src)?;
1661 }
1662 Instruction::Unary { dst, operand, .. } => {
1663 check_register(dst)?;
1664 check_register(operand)?;
1665 }
1666 Instruction::Binary {
1667 dst, left, right, ..
1668 } => {
1669 check_register(dst)?;
1670 check_register(left)?;
1671 check_register(right)?;
1672 }
1673 Instruction::CreateObject { dst }
1674 | Instruction::CreateArray { dst }
1675 | Instruction::CreateCell { dst } => {
1676 check_register(dst)?;
1677 }
1678 Instruction::CreateClosure {
1679 dst,
1680 function: reference,
1681 captures,
1682 } => {
1683 check_register(dst)?;
1684 check_register(captures)?;
1685 if reference.get() as usize >= function_count {
1686 return Err(instruction_error(
1687 function_index,
1688 pc,
1689 VerifyErrorKind::FunctionReferenceOutOfBounds {
1690 function: reference,
1691 function_count,
1692 },
1693 ));
1694 }
1695 }
1696 Instruction::GetProperty { dst, object, key } => {
1697 check_register(dst)?;
1698 check_register(object)?;
1699 check_register(key)?;
1700 }
1701 Instruction::SetProperty { object, key, value } => {
1702 check_register(object)?;
1703 check_register(key)?;
1704 check_register(value)?;
1705 }
1706 Instruction::DeleteProperty { dst, object, key } => {
1707 check_register(dst)?;
1708 check_register(object)?;
1709 check_register(key)?;
1710 }
1711 Instruction::DefineAccessor {
1712 object,
1713 key,
1714 accessor,
1715 ..
1716 } => {
1717 check_register(object)?;
1718 check_register(key)?;
1719 check_register(accessor)?;
1720 }
1721 Instruction::Call {
1722 dst,
1723 callee,
1724 this_value,
1725 arguments,
1726 } => {
1727 check_register(dst)?;
1728 check_register(callee)?;
1729 check_register(this_value)?;
1730 check_register(arguments)?;
1731 }
1732 Instruction::Construct {
1733 dst,
1734 callee,
1735 arguments,
1736 } => {
1737 check_register(dst)?;
1738 check_register(callee)?;
1739 check_register(arguments)?;
1740 }
1741 Instruction::LoadGlobal { dst, name } | Instruction::TypeOfGlobal { dst, name } => {
1742 check_register(dst)?;
1743 check_string_constant(name)?;
1744 }
1745 Instruction::StoreGlobal { name, value } => {
1746 check_string_constant(name)?;
1747 check_register(value)?;
1748 }
1749 Instruction::LoadThis { dst }
1750 | Instruction::LoadArguments { dst }
1751 | Instruction::LoadNewTarget { dst } => {
1752 check_register(dst)?;
1753 }
1754 Instruction::ArrayPush { array, value } => {
1755 check_register(array)?;
1756 check_register(value)?;
1757 }
1758 Instruction::ArrayExtend { array, iterable } => {
1759 check_register(array)?;
1760 check_register(iterable)?;
1761 }
1762 Instruction::ObjectSpread { target, source } => {
1763 check_register(target)?;
1764 check_register(source)?;
1765 }
1766 Instruction::SetPrototype { object, prototype } => {
1767 check_register(object)?;
1768 check_register(prototype)?;
1769 }
1770 Instruction::CreatePrivateName { dst, description } => {
1771 check_register(dst)?;
1772 check_string_constant(description)?;
1773 }
1774 Instruction::CreateRegExp {
1775 dst,
1776 pattern,
1777 flags,
1778 } => {
1779 check_register(dst)?;
1780 check_string_constant(pattern)?;
1781 check_string_constant(flags)?;
1782 }
1783 Instruction::GetIterator { dst, src, .. } => {
1784 check_register(dst)?;
1785 check_register(src)?;
1786 }
1787 Instruction::IteratorNext {
1788 done,
1789 value,
1790 iterator,
1791 } => {
1792 check_register(done)?;
1793 check_register(value)?;
1794 check_register(iterator)?;
1795 }
1796 Instruction::Jump { target } => verify_target(function_index, pc, target, code_len)?,
1797 Instruction::JumpIfTrue { condition, target }
1798 | Instruction::JumpIfFalse { condition, target } => {
1799 check_register(condition)?;
1800 verify_target(function_index, pc, target, code_len)?;
1801 }
1802 Instruction::Return { value } | Instruction::Throw { value } => check_register(value)?,
1803 Instruction::Suspend { dst, src, resume } => {
1804 check_register(dst)?;
1805 check_register(src)?;
1806 verify_target(function_index, pc, resume, code_len)?;
1807 }
1808 Instruction::Import { dst, specifier } => {
1809 check_register(dst)?;
1810 check_string_constant(specifier)?;
1811 }
1812 Instruction::Export { name, src } => {
1813 check_string_constant(name)?;
1814 check_register(src)?;
1815 }
1816 Instruction::Halt => {}
1817 }
1818
1819 let mut successor_error = None;
1822 instruction.visit_successors(pc as u32, |successor| {
1823 if successor_error.is_none() {
1824 successor_error = verify_target(function_index, pc, successor, code_len).err();
1825 }
1826 });
1827 if let Some(error) = successor_error {
1828 return Err(error);
1829 }
1830 Ok(())
1831}
1832
1833fn verify_target(
1834 function_index: usize,
1835 pc: usize,
1836 target: Pc,
1837 instruction_count: usize,
1838) -> Result<(), VerifyError> {
1839 if target.get() as usize >= instruction_count {
1840 Err(instruction_error(
1841 function_index,
1842 pc,
1843 VerifyErrorKind::JumpOutOfBounds {
1844 target: target.get(),
1845 instruction_count,
1846 },
1847 ))
1848 } else {
1849 Ok(())
1850 }
1851}
1852
1853fn definite_initialization(
1861 function_index: usize,
1862 function: &Function,
1863) -> Result<Certificate, VerifyError> {
1864 let register_count = function.register_count;
1865 let mut facts = vec![RegisterSet::full(register_count); function.code.len()];
1866 let mut entry = RegisterSet::empty(register_count);
1867 entry.insert_prefix(function.entry_initialized());
1868 facts[0] = entry;
1869
1870 loop {
1871 let mut changed = false;
1872 for (pc, instruction) in function.code.iter().copied().enumerate() {
1873 let mut after = facts[pc].clone();
1874 instruction.visit_writes(|write| after.insert(write));
1875 instruction.visit_successors(pc as u32, |successor| {
1876 changed |= facts[successor.get() as usize].intersect(&after);
1877 });
1878 }
1879 for handler in function.handlers.iter().copied() {
1880 let start = handler.start.get() as usize;
1881 let end = handler.end.get() as usize;
1882 let mut contribution = RegisterSet::full(register_count);
1883 for protected in &facts[start..end] {
1884 contribution.intersect(protected);
1885 }
1886 contribution.insert(handler.catch_register);
1887 changed |= facts[handler.handler.get() as usize].intersect(&contribution);
1888 }
1889 if !changed {
1890 break;
1891 }
1892 }
1893
1894 for (pc, instruction) in function.code.iter().copied().enumerate() {
1895 let mut missing = None;
1896 instruction.visit_reads(|register| {
1897 if missing.is_none() && !facts[pc].contains(register) {
1898 missing = Some(register);
1899 }
1900 });
1901 if let Some(register) = missing {
1902 return Err(instruction_error(
1903 function_index,
1904 pc,
1905 VerifyErrorKind::ReadBeforeWrite { register },
1906 ));
1907 }
1908 }
1909 Ok(Certificate {
1910 register_count,
1911 facts,
1912 })
1913}
1914
1915#[derive(Clone, Debug, Eq, PartialEq)]
1917pub struct DecodeLimits {
1918 pub max_bytes: usize,
1919 pub max_constants: u32,
1920 pub max_functions: u32,
1921 pub max_capture_count: u32,
1922 pub max_parameter_count: u32,
1923 pub max_register_count: u32,
1924 pub max_instructions_per_function: u32,
1925 pub max_total_instructions: u64,
1926 pub max_handlers_per_function: u32,
1927 pub max_string_units: u32,
1928 pub max_bigint_bytes: u32,
1929}
1930
1931impl Default for DecodeLimits {
1932 fn default() -> Self {
1933 Self {
1934 max_bytes: 16 * 1024 * 1024,
1935 max_constants: MAX_CONSTANTS,
1936 max_functions: MAX_FUNCTIONS,
1937 max_capture_count: MAX_REGISTERS,
1938 max_parameter_count: MAX_REGISTERS,
1939 max_register_count: MAX_REGISTERS,
1940 max_instructions_per_function: MAX_INSTRUCTIONS,
1941 max_total_instructions: 1 << 24,
1942 max_handlers_per_function: MAX_HANDLERS,
1943 max_string_units: 1 << 20,
1944 max_bigint_bytes: 1 << 20,
1945 }
1946 }
1947}
1948
1949#[derive(Clone, Debug, Eq, PartialEq)]
1950pub struct DecodeError {
1951 pub offset: usize,
1952 pub kind: DecodeErrorKind,
1953}
1954
1955#[derive(Clone, Debug, Eq, PartialEq)]
1956pub enum DecodeErrorKind {
1957 InputLimitExceeded {
1958 limit: usize,
1959 actual: usize,
1960 },
1961 UnexpectedEof,
1962 BadMagic {
1963 expected: u8,
1964 actual: u8,
1965 },
1966 UnsupportedVersion {
1967 version: u8,
1968 },
1969 MalformedInteger,
1970 NonCanonicalInteger,
1971 IntegerOverflow,
1972 InvalidConstantTag {
1973 tag: u8,
1974 },
1975 NonCanonicalNumber {
1976 bits: u64,
1977 },
1978 InvalidUtf8,
1979 InvalidBigInt,
1980 InvalidFunctionFlags {
1981 bits: u8,
1982 },
1983 InvalidUnaryOp {
1984 tag: u8,
1985 },
1986 InvalidBinaryOp {
1987 tag: u8,
1988 },
1989 InvalidIteratorKind {
1990 tag: u8,
1991 },
1992 InvalidAccessorKind {
1993 tag: u8,
1994 },
1995 InvalidOpcode {
1996 opcode: u8,
1997 },
1998 LimitExceeded {
1999 field: &'static str,
2000 limit: u64,
2001 actual: u64,
2002 },
2003 TrailingBytes {
2004 count: usize,
2005 },
2006}
2007
2008impl fmt::Display for DecodeError {
2009 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2010 write!(formatter, "byte {}: ", self.offset)?;
2011 match self.kind {
2012 DecodeErrorKind::InputLimitExceeded { limit, actual } => {
2013 write!(formatter, "input has {actual} bytes, limit is {limit}")
2014 }
2015 DecodeErrorKind::UnexpectedEof => formatter.write_str("unexpected end of input"),
2016 DecodeErrorKind::BadMagic { expected, actual } => write!(
2017 formatter,
2018 "bad magic byte {actual:#04x}, expected {expected:#04x}"
2019 ),
2020 DecodeErrorKind::UnsupportedVersion { version } => {
2021 write!(formatter, "unsupported format version {version}")
2022 }
2023 DecodeErrorKind::MalformedInteger => formatter.write_str("malformed LEB128 integer"),
2024 DecodeErrorKind::NonCanonicalInteger => {
2025 formatter.write_str("noncanonical (overlong) LEB128 integer")
2026 }
2027 DecodeErrorKind::IntegerOverflow => {
2028 formatter.write_str("LEB128 integer exceeds 32 bits")
2029 }
2030 DecodeErrorKind::InvalidConstantTag { tag } => {
2031 write!(formatter, "invalid constant tag {tag}")
2032 }
2033 DecodeErrorKind::NonCanonicalNumber { bits } => {
2034 write!(formatter, "noncanonical NaN bits {bits:#018x}")
2035 }
2036 DecodeErrorKind::InvalidUtf8 => formatter.write_str("bigint text is not UTF-8"),
2037 DecodeErrorKind::InvalidBigInt => {
2038 formatter.write_str("bigint constant is not canonical decimal text")
2039 }
2040 DecodeErrorKind::InvalidFunctionFlags { bits } => {
2041 write!(formatter, "invalid function flags {bits:#04x}")
2042 }
2043 DecodeErrorKind::InvalidUnaryOp { tag } => {
2044 write!(formatter, "invalid unary operator {tag}")
2045 }
2046 DecodeErrorKind::InvalidBinaryOp { tag } => {
2047 write!(formatter, "invalid binary operator {tag}")
2048 }
2049 DecodeErrorKind::InvalidIteratorKind { tag } => {
2050 write!(formatter, "invalid iterator kind {tag}")
2051 }
2052 DecodeErrorKind::InvalidAccessorKind { tag } => {
2053 write!(formatter, "invalid accessor kind {tag}")
2054 }
2055 DecodeErrorKind::InvalidOpcode { opcode } => {
2056 write!(formatter, "invalid opcode {opcode}")
2057 }
2058 DecodeErrorKind::LimitExceeded {
2059 field,
2060 limit,
2061 actual,
2062 } => write!(formatter, "{field} value {actual} exceeds limit {limit}"),
2063 DecodeErrorKind::TrailingBytes { count } => write!(formatter, "{count} trailing bytes"),
2064 }
2065 }
2066}
2067
2068impl Error for DecodeError {}
2069
2070#[derive(Clone, Debug, Eq, PartialEq)]
2071pub enum LoadError {
2072 Decode(DecodeError),
2073 Verify(VerifyError),
2074}
2075
2076impl fmt::Display for LoadError {
2077 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
2078 match self {
2079 Self::Decode(error) => error.fmt(formatter),
2080 Self::Verify(error) => error.fmt(formatter),
2081 }
2082 }
2083}
2084
2085impl Error for LoadError {
2086 fn source(&self) -> Option<&(dyn Error + 'static)> {
2087 match self {
2088 Self::Decode(error) => Some(error),
2089 Self::Verify(error) => Some(error),
2090 }
2091 }
2092}
2093
2094pub fn decode(bytes: &[u8], limits: &DecodeLimits) -> Result<Module<Unverified>, DecodeError> {
2101 if bytes.len() > limits.max_bytes {
2102 return Err(DecodeError {
2103 offset: 0,
2104 kind: DecodeErrorKind::InputLimitExceeded {
2105 limit: limits.max_bytes,
2106 actual: bytes.len(),
2107 },
2108 });
2109 }
2110 let mut decoder = Decoder {
2111 bytes,
2112 offset: 0,
2113 limits,
2114 total_instructions: 0,
2115 };
2116 let module = decoder.module()?;
2117 if decoder.offset != bytes.len() {
2118 return Err(DecodeError {
2119 offset: decoder.offset,
2120 kind: DecodeErrorKind::TrailingBytes {
2121 count: bytes.len() - decoder.offset,
2122 },
2123 });
2124 }
2125 Ok(module)
2126}
2127
2128pub fn decode_verified(bytes: &[u8], limits: &DecodeLimits) -> Result<Module<Verified>, LoadError> {
2134 decode(bytes, limits)
2135 .map_err(LoadError::Decode)?
2136 .verify()
2137 .map_err(LoadError::Verify)
2138}
2139
2140struct Decoder<'a> {
2141 bytes: &'a [u8],
2142 offset: usize,
2143 limits: &'a DecodeLimits,
2144 total_instructions: u64,
2145}
2146
2147impl<'a> Decoder<'a> {
2148 fn module(&mut self) -> Result<Module<Unverified>, DecodeError> {
2149 for expected in MAGIC {
2150 let at = self.offset;
2151 let actual = self.byte()?;
2152 if actual != expected {
2153 return Err(self.error(at, DecodeErrorKind::BadMagic { expected, actual }));
2154 }
2155 }
2156 let version_at = self.offset;
2157 let version = self.byte()?;
2158 if version != FORMAT_VERSION {
2159 return Err(self.error(version_at, DecodeErrorKind::UnsupportedVersion { version }));
2160 }
2161
2162 let constant_count = self.bounded("constant count", self.limits.max_constants)?;
2163 let mut constants = Vec::with_capacity(self.cap(constant_count));
2164 for _ in 0..constant_count {
2165 constants.push(self.constant()?);
2166 }
2167
2168 let function_count = self.bounded("function count", self.limits.max_functions)?;
2169 let entry = FunctionId::new(self.leb128()?);
2170 let mut functions = Vec::with_capacity(self.cap(function_count));
2171 for _ in 0..function_count {
2172 functions.push(self.function()?);
2173 }
2174 Ok(Module::new(constants, functions, entry))
2175 }
2176
2177 fn constant(&mut self) -> Result<Constant, DecodeError> {
2178 let tag_at = self.offset;
2179 match self.byte()? {
2180 0 => {
2181 let number_at = self.offset;
2182 let bits = u64::from_le_bytes(self.exact::<8>()?);
2183 NumberBits::from_wire(bits)
2184 .map(Constant::Number)
2185 .ok_or_else(|| {
2186 self.error(number_at, DecodeErrorKind::NonCanonicalNumber { bits })
2187 })
2188 }
2189 1 => Ok(Constant::Int32(i32::from_le_bytes(self.exact::<4>()?))),
2190 2 => Ok(Constant::String(self.string()?)),
2191 3 => Ok(Constant::Boolean(false)),
2192 4 => Ok(Constant::Boolean(true)),
2193 5 => Ok(Constant::Null),
2194 6 => Ok(Constant::Undefined),
2195 7 => {
2196 let start = self.offset;
2197 let text = self.text()?;
2198 BigIntLiteral::new(text)
2199 .map(Constant::BigInt)
2200 .ok_or_else(|| self.error(start, DecodeErrorKind::InvalidBigInt))
2201 }
2202 tag => Err(self.error(tag_at, DecodeErrorKind::InvalidConstantTag { tag })),
2203 }
2204 }
2205
2206 fn string(&mut self) -> Result<EcmaString, DecodeError> {
2207 let unit_count = self.bounded("string unit count", self.limits.max_string_units)?;
2208 let byte_count = usize::try_from(unit_count)
2209 .ok()
2210 .and_then(|units| units.checked_mul(2))
2211 .ok_or_else(|| self.error(self.offset, DecodeErrorKind::UnexpectedEof))?;
2212 let bytes = self.slice(byte_count)?;
2213 Ok(EcmaString::from_le_bytes(bytes))
2214 }
2215
2216 fn text(&mut self) -> Result<String, DecodeError> {
2217 let length = self.bounded("bigint byte length", self.limits.max_bigint_bytes)?;
2218 let start = self.offset;
2219 let bytes = self.slice(length as usize)?;
2220 let value = std::str::from_utf8(bytes)
2221 .map_err(|_| self.error(start, DecodeErrorKind::InvalidUtf8))?;
2222 Ok(value.to_owned())
2223 }
2224
2225 fn function(&mut self) -> Result<Function, DecodeError> {
2226 let name = match self.leb128()? {
2227 0 => None,
2228 encoded => Some(ConstantId::new(encoded - 1)),
2229 };
2230 let capture_count = self.bounded("capture count", self.limits.max_capture_count)?;
2231 let parameter_count = self.bounded("parameter count", self.limits.max_parameter_count)?;
2232 let register_count = self.bounded("register count", self.limits.max_register_count)?;
2233 let flags_at = self.offset;
2234 let flags_bits = self.byte()?;
2235 let flags = FunctionFlags::from_bits(flags_bits).ok_or_else(|| {
2236 self.error(
2237 flags_at,
2238 DecodeErrorKind::InvalidFunctionFlags { bits: flags_bits },
2239 )
2240 })?;
2241 let instruction_at = self.offset;
2242 let instruction_count = self.bounded(
2243 "instruction count",
2244 self.limits.max_instructions_per_function,
2245 )?;
2246 self.total_instructions += u64::from(instruction_count);
2247 if self.total_instructions > self.limits.max_total_instructions {
2248 return Err(self.error(
2249 instruction_at,
2250 DecodeErrorKind::LimitExceeded {
2251 field: "total instruction count",
2252 limit: self.limits.max_total_instructions,
2253 actual: self.total_instructions,
2254 },
2255 ));
2256 }
2257 let mut code = Vec::with_capacity(self.cap(instruction_count));
2258 for _ in 0..instruction_count {
2259 code.push(self.instruction()?);
2260 }
2261
2262 let handler_count = self.bounded("handler count", self.limits.max_handlers_per_function)?;
2263 let mut handlers = Vec::with_capacity(self.cap(handler_count));
2264 for _ in 0..handler_count {
2265 handlers.push(ExceptionHandler {
2266 start: Pc::new(self.leb128()?),
2267 end: Pc::new(self.leb128()?),
2268 handler: Pc::new(self.leb128()?),
2269 catch_register: Register::new(self.leb128()?),
2270 });
2271 }
2272 Ok(Function::new(
2273 name,
2274 capture_count,
2275 parameter_count,
2276 register_count,
2277 flags,
2278 code,
2279 handlers,
2280 ))
2281 }
2282
2283 fn instruction(&mut self) -> Result<Instruction, DecodeError> {
2284 let opcode_at = self.offset;
2285 match self.byte()? {
2286 0 => Ok(Instruction::LoadConst {
2287 dst: Register::new(self.leb128()?),
2288 constant: ConstantId::new(self.leb128()?),
2289 }),
2290 1 => Ok(Instruction::Move {
2291 dst: Register::new(self.leb128()?),
2292 src: Register::new(self.leb128()?),
2293 }),
2294 2 => Ok(Instruction::Unary {
2295 dst: Register::new(self.leb128()?),
2296 op: self.unary_op()?,
2297 operand: Register::new(self.leb128()?),
2298 }),
2299 3 => Ok(Instruction::Binary {
2300 dst: Register::new(self.leb128()?),
2301 op: self.binary_op()?,
2302 left: Register::new(self.leb128()?),
2303 right: Register::new(self.leb128()?),
2304 }),
2305 4 => Ok(Instruction::CreateObject {
2306 dst: Register::new(self.leb128()?),
2307 }),
2308 5 => Ok(Instruction::CreateArray {
2309 dst: Register::new(self.leb128()?),
2310 }),
2311 6 => Ok(Instruction::CreateClosure {
2312 dst: Register::new(self.leb128()?),
2313 function: FunctionId::new(self.leb128()?),
2314 captures: Register::new(self.leb128()?),
2315 }),
2316 7 => Ok(Instruction::GetProperty {
2317 dst: Register::new(self.leb128()?),
2318 object: Register::new(self.leb128()?),
2319 key: Register::new(self.leb128()?),
2320 }),
2321 8 => Ok(Instruction::SetProperty {
2322 object: Register::new(self.leb128()?),
2323 key: Register::new(self.leb128()?),
2324 value: Register::new(self.leb128()?),
2325 }),
2326 9 => Ok(Instruction::DeleteProperty {
2327 dst: Register::new(self.leb128()?),
2328 object: Register::new(self.leb128()?),
2329 key: Register::new(self.leb128()?),
2330 }),
2331 10 => Ok(Instruction::DefineAccessor {
2332 object: Register::new(self.leb128()?),
2333 key: Register::new(self.leb128()?),
2334 accessor: Register::new(self.leb128()?),
2335 kind: self.accessor_kind()?,
2336 }),
2337 11 => Ok(Instruction::Call {
2338 dst: Register::new(self.leb128()?),
2339 callee: Register::new(self.leb128()?),
2340 this_value: Register::new(self.leb128()?),
2341 arguments: Register::new(self.leb128()?),
2342 }),
2343 12 => Ok(Instruction::Construct {
2344 dst: Register::new(self.leb128()?),
2345 callee: Register::new(self.leb128()?),
2346 arguments: Register::new(self.leb128()?),
2347 }),
2348 13 => Ok(Instruction::LoadGlobal {
2349 dst: Register::new(self.leb128()?),
2350 name: ConstantId::new(self.leb128()?),
2351 }),
2352 14 => Ok(Instruction::StoreGlobal {
2353 name: ConstantId::new(self.leb128()?),
2354 value: Register::new(self.leb128()?),
2355 }),
2356 15 => Ok(Instruction::TypeOfGlobal {
2357 dst: Register::new(self.leb128()?),
2358 name: ConstantId::new(self.leb128()?),
2359 }),
2360 16 => Ok(Instruction::LoadThis {
2361 dst: Register::new(self.leb128()?),
2362 }),
2363 17 => Ok(Instruction::LoadArguments {
2364 dst: Register::new(self.leb128()?),
2365 }),
2366 18 => Ok(Instruction::LoadNewTarget {
2367 dst: Register::new(self.leb128()?),
2368 }),
2369 19 => Ok(Instruction::ArrayPush {
2370 array: Register::new(self.leb128()?),
2371 value: Register::new(self.leb128()?),
2372 }),
2373 20 => Ok(Instruction::ArrayExtend {
2374 array: Register::new(self.leb128()?),
2375 iterable: Register::new(self.leb128()?),
2376 }),
2377 21 => Ok(Instruction::ObjectSpread {
2378 target: Register::new(self.leb128()?),
2379 source: Register::new(self.leb128()?),
2380 }),
2381 22 => Ok(Instruction::SetPrototype {
2382 object: Register::new(self.leb128()?),
2383 prototype: Register::new(self.leb128()?),
2384 }),
2385 23 => Ok(Instruction::CreatePrivateName {
2386 dst: Register::new(self.leb128()?),
2387 description: ConstantId::new(self.leb128()?),
2388 }),
2389 24 => Ok(Instruction::CreateRegExp {
2390 dst: Register::new(self.leb128()?),
2391 pattern: ConstantId::new(self.leb128()?),
2392 flags: ConstantId::new(self.leb128()?),
2393 }),
2394 25 => Ok(Instruction::GetIterator {
2395 dst: Register::new(self.leb128()?),
2396 src: Register::new(self.leb128()?),
2397 kind: self.iterator_kind()?,
2398 }),
2399 26 => Ok(Instruction::IteratorNext {
2400 done: Register::new(self.leb128()?),
2401 value: Register::new(self.leb128()?),
2402 iterator: Register::new(self.leb128()?),
2403 }),
2404 27 => Ok(Instruction::Jump {
2405 target: Pc::new(self.leb128()?),
2406 }),
2407 28 => Ok(Instruction::JumpIfTrue {
2408 condition: Register::new(self.leb128()?),
2409 target: Pc::new(self.leb128()?),
2410 }),
2411 29 => Ok(Instruction::JumpIfFalse {
2412 condition: Register::new(self.leb128()?),
2413 target: Pc::new(self.leb128()?),
2414 }),
2415 30 => Ok(Instruction::Return {
2416 value: Register::new(self.leb128()?),
2417 }),
2418 31 => Ok(Instruction::Throw {
2419 value: Register::new(self.leb128()?),
2420 }),
2421 32 => Ok(Instruction::Suspend {
2422 dst: Register::new(self.leb128()?),
2423 src: Register::new(self.leb128()?),
2424 resume: Pc::new(self.leb128()?),
2425 }),
2426 33 => Ok(Instruction::Import {
2427 dst: Register::new(self.leb128()?),
2428 specifier: ConstantId::new(self.leb128()?),
2429 }),
2430 34 => Ok(Instruction::Export {
2431 name: ConstantId::new(self.leb128()?),
2432 src: Register::new(self.leb128()?),
2433 }),
2434 35 => Ok(Instruction::Halt),
2435 36 => Ok(Instruction::CreateCell {
2436 dst: Register::new(self.leb128()?),
2437 }),
2438 opcode => Err(self.error(opcode_at, DecodeErrorKind::InvalidOpcode { opcode })),
2439 }
2440 }
2441
2442 fn unary_op(&mut self) -> Result<UnaryOp, DecodeError> {
2443 let at = self.offset;
2444 let tag = self.byte()?;
2445 UnaryOp::from_u8(tag).ok_or_else(|| self.error(at, DecodeErrorKind::InvalidUnaryOp { tag }))
2446 }
2447
2448 fn binary_op(&mut self) -> Result<BinaryOp, DecodeError> {
2449 let at = self.offset;
2450 let tag = self.byte()?;
2451 BinaryOp::from_u8(tag)
2452 .ok_or_else(|| self.error(at, DecodeErrorKind::InvalidBinaryOp { tag }))
2453 }
2454
2455 fn iterator_kind(&mut self) -> Result<IteratorKind, DecodeError> {
2456 let at = self.offset;
2457 let tag = self.byte()?;
2458 IteratorKind::from_u8(tag)
2459 .ok_or_else(|| self.error(at, DecodeErrorKind::InvalidIteratorKind { tag }))
2460 }
2461
2462 fn accessor_kind(&mut self) -> Result<AccessorKind, DecodeError> {
2463 let at = self.offset;
2464 let tag = self.byte()?;
2465 AccessorKind::from_u8(tag)
2466 .ok_or_else(|| self.error(at, DecodeErrorKind::InvalidAccessorKind { tag }))
2467 }
2468
2469 fn bounded(&mut self, field: &'static str, limit: u32) -> Result<u32, DecodeError> {
2470 let at = self.offset;
2471 let actual = self.leb128()?;
2472 if actual > limit {
2473 Err(self.error(
2474 at,
2475 DecodeErrorKind::LimitExceeded {
2476 field,
2477 limit: u64::from(limit),
2478 actual: u64::from(actual),
2479 },
2480 ))
2481 } else {
2482 Ok(actual)
2483 }
2484 }
2485
2486 fn leb128(&mut self) -> Result<u32, DecodeError> {
2489 let start = self.offset;
2490 let mut result: u32 = 0;
2491 let mut shift: u32 = 0;
2492 loop {
2493 let byte = self.byte()?;
2494 if shift == 28 {
2495 if byte & 0x80 != 0 || byte > 0x0f {
2499 return Err(self.error(start, DecodeErrorKind::IntegerOverflow));
2500 }
2501 if byte == 0 {
2502 return Err(self.error(start, DecodeErrorKind::NonCanonicalInteger));
2503 }
2504 return Ok(result | (u32::from(byte) << 28));
2505 }
2506 result |= u32::from(byte & 0x7f) << shift;
2507 if byte & 0x80 == 0 {
2508 if byte == 0 && self.offset - start > 1 {
2509 return Err(self.error(start, DecodeErrorKind::NonCanonicalInteger));
2510 }
2511 return Ok(result);
2512 }
2513 shift += 7;
2514 }
2515 }
2516
2517 fn cap(&self, count: u32) -> usize {
2518 (count as usize).min(self.bytes.len().saturating_sub(self.offset))
2521 }
2522
2523 fn byte(&mut self) -> Result<u8, DecodeError> {
2524 let Some(byte) = self.bytes.get(self.offset).copied() else {
2525 return Err(self.error(self.offset, DecodeErrorKind::UnexpectedEof));
2526 };
2527 self.offset += 1;
2528 Ok(byte)
2529 }
2530
2531 fn exact<const N: usize>(&mut self) -> Result<[u8; N], DecodeError> {
2532 let bytes = self.slice(N)?;
2533 let mut result = [0; N];
2534 result.copy_from_slice(bytes);
2535 Ok(result)
2536 }
2537
2538 fn slice(&mut self, length: usize) -> Result<&'a [u8], DecodeError> {
2539 let source: &'a [u8] = self.bytes;
2540 let Some(end) = self.offset.checked_add(length) else {
2541 return Err(self.error(self.offset, DecodeErrorKind::UnexpectedEof));
2542 };
2543 let Some(bytes) = source.get(self.offset..end) else {
2544 return Err(self.error(self.offset, DecodeErrorKind::UnexpectedEof));
2545 };
2546 self.offset = end;
2547 Ok(bytes)
2548 }
2549
2550 const fn error(&self, offset: usize, kind: DecodeErrorKind) -> DecodeError {
2551 DecodeError { offset, kind }
2552 }
2553}
2554
2555fn write_u32(value: u32, output: &mut Vec<u8>) {
2556 let mut remaining = value;
2557 loop {
2558 let byte = (remaining & 0x7f) as u8;
2559 remaining >>= 7;
2560 if remaining == 0 {
2561 output.push(byte);
2562 return;
2563 }
2564 output.push(byte | 0x80);
2565 }
2566}
2567
2568fn encode_constant(constant: &Constant, output: &mut Vec<u8>) {
2569 match constant {
2570 Constant::Number(bits) => {
2571 output.push(0);
2572 output.extend_from_slice(&bits.bits().to_le_bytes());
2573 }
2574 Constant::Int32(value) => {
2575 output.push(1);
2576 output.extend_from_slice(&value.to_le_bytes());
2577 }
2578 Constant::String(value) => {
2579 output.push(2);
2580 write_string(value, output);
2581 }
2582 Constant::Boolean(false) => output.push(3),
2583 Constant::Boolean(true) => output.push(4),
2584 Constant::Null => output.push(5),
2585 Constant::Undefined => output.push(6),
2586 Constant::BigInt(value) => {
2587 output.push(7);
2588 write_text(value.as_str(), output);
2589 }
2590 }
2591}
2592
2593fn write_string(value: &EcmaString, output: &mut Vec<u8>) {
2594 write_u32(value.len_units() as u32, output);
2595 for unit in value.as_units() {
2596 output.extend_from_slice(&unit.to_le_bytes());
2597 }
2598}
2599
2600fn write_text(value: &str, output: &mut Vec<u8>) {
2601 write_u32(value.len() as u32, output);
2602 output.extend_from_slice(value.as_bytes());
2603}
2604
2605fn encode_function(function: &Function, output: &mut Vec<u8>) {
2606 write_u32(function.name.map_or(0, |name| name.get() + 1), output);
2607 write_u32(function.capture_count, output);
2608 write_u32(function.parameter_count, output);
2609 write_u32(function.register_count, output);
2610 output.push(function.flags.to_bits());
2611 write_u32(function.code.len() as u32, output);
2612 for instruction in &function.code {
2613 encode_instruction(*instruction, output);
2614 }
2615 write_u32(function.handlers.len() as u32, output);
2616 for handler in &function.handlers {
2617 write_u32(handler.start.get(), output);
2618 write_u32(handler.end.get(), output);
2619 write_u32(handler.handler.get(), output);
2620 write_u32(handler.catch_register.get(), output);
2621 }
2622}
2623
2624fn encode_instruction(instruction: Instruction, output: &mut Vec<u8>) {
2625 match instruction {
2626 Instruction::LoadConst { dst, constant } => {
2627 output.push(0);
2628 write_u32(dst.get(), output);
2629 write_u32(constant.get(), output);
2630 }
2631 Instruction::Move { dst, src } => {
2632 output.push(1);
2633 write_u32(dst.get(), output);
2634 write_u32(src.get(), output);
2635 }
2636 Instruction::Unary { dst, op, operand } => {
2637 output.push(2);
2638 write_u32(dst.get(), output);
2639 output.push(op.to_u8());
2640 write_u32(operand.get(), output);
2641 }
2642 Instruction::Binary {
2643 dst,
2644 op,
2645 left,
2646 right,
2647 } => {
2648 output.push(3);
2649 write_u32(dst.get(), output);
2650 output.push(op.to_u8());
2651 write_u32(left.get(), output);
2652 write_u32(right.get(), output);
2653 }
2654 Instruction::CreateObject { dst } => {
2655 output.push(4);
2656 write_u32(dst.get(), output);
2657 }
2658 Instruction::CreateArray { dst } => {
2659 output.push(5);
2660 write_u32(dst.get(), output);
2661 }
2662 Instruction::CreateClosure {
2663 dst,
2664 function,
2665 captures,
2666 } => {
2667 output.push(6);
2668 write_u32(dst.get(), output);
2669 write_u32(function.get(), output);
2670 write_u32(captures.get(), output);
2671 }
2672 Instruction::GetProperty { dst, object, key } => {
2673 output.push(7);
2674 write_u32(dst.get(), output);
2675 write_u32(object.get(), output);
2676 write_u32(key.get(), output);
2677 }
2678 Instruction::SetProperty { object, key, value } => {
2679 output.push(8);
2680 write_u32(object.get(), output);
2681 write_u32(key.get(), output);
2682 write_u32(value.get(), output);
2683 }
2684 Instruction::DeleteProperty { dst, object, key } => {
2685 output.push(9);
2686 write_u32(dst.get(), output);
2687 write_u32(object.get(), output);
2688 write_u32(key.get(), output);
2689 }
2690 Instruction::DefineAccessor {
2691 object,
2692 key,
2693 accessor,
2694 kind,
2695 } => {
2696 output.push(10);
2697 write_u32(object.get(), output);
2698 write_u32(key.get(), output);
2699 write_u32(accessor.get(), output);
2700 output.push(kind.to_u8());
2701 }
2702 Instruction::Call {
2703 dst,
2704 callee,
2705 this_value,
2706 arguments,
2707 } => {
2708 output.push(11);
2709 write_u32(dst.get(), output);
2710 write_u32(callee.get(), output);
2711 write_u32(this_value.get(), output);
2712 write_u32(arguments.get(), output);
2713 }
2714 Instruction::Construct {
2715 dst,
2716 callee,
2717 arguments,
2718 } => {
2719 output.push(12);
2720 write_u32(dst.get(), output);
2721 write_u32(callee.get(), output);
2722 write_u32(arguments.get(), output);
2723 }
2724 Instruction::LoadGlobal { dst, name } => {
2725 output.push(13);
2726 write_u32(dst.get(), output);
2727 write_u32(name.get(), output);
2728 }
2729 Instruction::StoreGlobal { name, value } => {
2730 output.push(14);
2731 write_u32(name.get(), output);
2732 write_u32(value.get(), output);
2733 }
2734 Instruction::TypeOfGlobal { dst, name } => {
2735 output.push(15);
2736 write_u32(dst.get(), output);
2737 write_u32(name.get(), output);
2738 }
2739 Instruction::LoadThis { dst } => {
2740 output.push(16);
2741 write_u32(dst.get(), output);
2742 }
2743 Instruction::LoadArguments { dst } => {
2744 output.push(17);
2745 write_u32(dst.get(), output);
2746 }
2747 Instruction::LoadNewTarget { dst } => {
2748 output.push(18);
2749 write_u32(dst.get(), output);
2750 }
2751 Instruction::ArrayPush { array, value } => {
2752 output.push(19);
2753 write_u32(array.get(), output);
2754 write_u32(value.get(), output);
2755 }
2756 Instruction::ArrayExtend { array, iterable } => {
2757 output.push(20);
2758 write_u32(array.get(), output);
2759 write_u32(iterable.get(), output);
2760 }
2761 Instruction::ObjectSpread { target, source } => {
2762 output.push(21);
2763 write_u32(target.get(), output);
2764 write_u32(source.get(), output);
2765 }
2766 Instruction::SetPrototype { object, prototype } => {
2767 output.push(22);
2768 write_u32(object.get(), output);
2769 write_u32(prototype.get(), output);
2770 }
2771 Instruction::CreatePrivateName { dst, description } => {
2772 output.push(23);
2773 write_u32(dst.get(), output);
2774 write_u32(description.get(), output);
2775 }
2776 Instruction::CreateRegExp {
2777 dst,
2778 pattern,
2779 flags,
2780 } => {
2781 output.push(24);
2782 write_u32(dst.get(), output);
2783 write_u32(pattern.get(), output);
2784 write_u32(flags.get(), output);
2785 }
2786 Instruction::GetIterator { dst, src, kind } => {
2787 output.push(25);
2788 write_u32(dst.get(), output);
2789 write_u32(src.get(), output);
2790 output.push(kind.to_u8());
2791 }
2792 Instruction::IteratorNext {
2793 done,
2794 value,
2795 iterator,
2796 } => {
2797 output.push(26);
2798 write_u32(done.get(), output);
2799 write_u32(value.get(), output);
2800 write_u32(iterator.get(), output);
2801 }
2802 Instruction::Jump { target } => {
2803 output.push(27);
2804 write_u32(target.get(), output);
2805 }
2806 Instruction::JumpIfTrue { condition, target } => {
2807 output.push(28);
2808 write_u32(condition.get(), output);
2809 write_u32(target.get(), output);
2810 }
2811 Instruction::JumpIfFalse { condition, target } => {
2812 output.push(29);
2813 write_u32(condition.get(), output);
2814 write_u32(target.get(), output);
2815 }
2816 Instruction::Return { value } => {
2817 output.push(30);
2818 write_u32(value.get(), output);
2819 }
2820 Instruction::Throw { value } => {
2821 output.push(31);
2822 write_u32(value.get(), output);
2823 }
2824 Instruction::Suspend { dst, src, resume } => {
2825 output.push(32);
2826 write_u32(dst.get(), output);
2827 write_u32(src.get(), output);
2828 write_u32(resume.get(), output);
2829 }
2830 Instruction::Import { dst, specifier } => {
2831 output.push(33);
2832 write_u32(dst.get(), output);
2833 write_u32(specifier.get(), output);
2834 }
2835 Instruction::Export { name, src } => {
2836 output.push(34);
2837 write_u32(name.get(), output);
2838 write_u32(src.get(), output);
2839 }
2840 Instruction::Halt => output.push(35),
2841 Instruction::CreateCell { dst } => {
2842 output.push(36);
2843 write_u32(dst.get(), output);
2844 }
2845 }
2846}
2847
2848#[cfg(test)]
2849mod tests {
2850 use super::*;
2851
2852 fn flags() -> FunctionFlags {
2853 FunctionFlags::default()
2854 }
2855
2856 fn prefix() -> Vec<u8> {
2857 let mut bytes = MAGIC.to_vec();
2858 bytes.push(FORMAT_VERSION);
2859 bytes
2860 }
2861
2862 fn rich_module() -> Module<Unverified> {
2878 let constants = vec![
2879 Constant::String(EcmaString::from_utf8("main")), Constant::Int32(21), Constant::Number(NumberBits::from_f64(1.5)), Constant::BigInt(BigIntLiteral::new("-1234567890123".to_owned()).unwrap()), Constant::Boolean(true), Constant::Null, Constant::Undefined, Constant::String(EcmaString::from_utf8("./dep")), Constant::String(EcmaString::from_utf8("g")), Constant::String(EcmaString::from_utf8("#p")), Constant::String(EcmaString::from_utf8("ab")), Constant::String(EcmaString::from_utf8("gi")), Constant::String(EcmaString::from_utf8("x")), ];
2893 let code = vec![
2894 Instruction::LoadConst {
2895 dst: Register::new(0),
2896 constant: ConstantId::new(1),
2897 },
2898 Instruction::LoadConst {
2899 dst: Register::new(1),
2900 constant: ConstantId::new(2),
2901 },
2902 Instruction::Binary {
2903 dst: Register::new(2),
2904 op: BinaryOp::Add,
2905 left: Register::new(0),
2906 right: Register::new(1),
2907 },
2908 Instruction::Unary {
2909 dst: Register::new(3),
2910 op: UnaryOp::Negate,
2911 operand: Register::new(2),
2912 },
2913 Instruction::CreateObject {
2914 dst: Register::new(4),
2915 },
2916 Instruction::LoadConst {
2917 dst: Register::new(5),
2918 constant: ConstantId::new(0),
2919 },
2920 Instruction::SetProperty {
2921 object: Register::new(4),
2922 key: Register::new(5),
2923 value: Register::new(3),
2924 },
2925 Instruction::GetProperty {
2926 dst: Register::new(6),
2927 object: Register::new(4),
2928 key: Register::new(5),
2929 },
2930 Instruction::CreateArray {
2931 dst: Register::new(7),
2932 },
2933 Instruction::ArrayPush {
2934 array: Register::new(7),
2935 value: Register::new(6),
2936 },
2937 Instruction::ArrayExtend {
2938 array: Register::new(7),
2939 iterable: Register::new(7),
2940 },
2941 Instruction::CreateObject {
2942 dst: Register::new(9),
2943 },
2944 Instruction::ObjectSpread {
2945 target: Register::new(9),
2946 source: Register::new(4),
2947 },
2948 Instruction::SetPrototype {
2949 object: Register::new(9),
2950 prototype: Register::new(4),
2951 },
2952 Instruction::CreateClosure {
2953 dst: Register::new(10),
2954 function: FunctionId::new(0),
2955 captures: Register::new(7),
2956 },
2957 Instruction::LoadThis {
2958 dst: Register::new(11),
2959 },
2960 Instruction::LoadArguments {
2961 dst: Register::new(12),
2962 },
2963 Instruction::LoadNewTarget {
2964 dst: Register::new(13),
2965 },
2966 Instruction::LoadGlobal {
2967 dst: Register::new(14),
2968 name: ConstantId::new(8),
2969 },
2970 Instruction::StoreGlobal {
2971 name: ConstantId::new(8),
2972 value: Register::new(14),
2973 },
2974 Instruction::TypeOfGlobal {
2975 dst: Register::new(15),
2976 name: ConstantId::new(8),
2977 },
2978 Instruction::CreatePrivateName {
2979 dst: Register::new(16),
2980 description: ConstantId::new(9),
2981 },
2982 Instruction::CreateRegExp {
2983 dst: Register::new(17),
2984 pattern: ConstantId::new(10),
2985 flags: ConstantId::new(11),
2986 },
2987 Instruction::GetIterator {
2988 dst: Register::new(18),
2989 src: Register::new(7),
2990 kind: IteratorKind::Sync,
2991 },
2992 Instruction::IteratorNext {
2993 done: Register::new(19),
2994 value: Register::new(20),
2995 iterator: Register::new(18),
2996 },
2997 Instruction::DefineAccessor {
2998 object: Register::new(9),
2999 key: Register::new(5),
3000 accessor: Register::new(10),
3001 kind: AccessorKind::Getter,
3002 },
3003 Instruction::Call {
3004 dst: Register::new(21),
3005 callee: Register::new(10),
3006 this_value: Register::new(4),
3007 arguments: Register::new(7),
3008 },
3009 Instruction::Construct {
3010 dst: Register::new(22),
3011 callee: Register::new(10),
3012 arguments: Register::new(7),
3013 },
3014 Instruction::Import {
3015 dst: Register::new(23),
3016 specifier: ConstantId::new(7),
3017 },
3018 Instruction::Export {
3019 name: ConstantId::new(12),
3020 src: Register::new(23),
3021 },
3022 Instruction::Suspend {
3023 dst: Register::new(24),
3024 src: Register::new(22),
3025 resume: Pc::new(31),
3026 },
3027 Instruction::JumpIfTrue {
3028 condition: Register::new(21),
3029 target: Pc::new(33),
3030 },
3031 Instruction::Return {
3032 value: Register::new(6),
3033 },
3034 Instruction::Return {
3035 value: Register::new(24),
3036 },
3037 Instruction::Return {
3038 value: Register::new(25),
3039 },
3040 ];
3041 let handlers = vec![ExceptionHandler {
3042 start: Pc::new(0),
3043 end: Pc::new(34),
3044 handler: Pc::new(34),
3045 catch_register: Register::new(25),
3046 }];
3047 Module::new(
3048 constants,
3049 vec![Function::new(
3050 Some(ConstantId::new(0)),
3051 0,
3052 0,
3053 26,
3054 FunctionFlags {
3055 is_async: true,
3056 is_generator: false,
3057 },
3058 code,
3059 handlers,
3060 )],
3061 FunctionId::new(0),
3062 )
3063 }
3064
3065 #[test]
3066 fn rich_module_verifies_round_trips_and_is_deterministic() {
3067 let verified = rich_module().verify().expect("valid production module");
3068 let encoded = verified.encode();
3069 assert_eq!(verified.encode(), encoded, "encoding is deterministic");
3070
3071 let decoded = decode(&encoded, &DecodeLimits::default()).expect("canonical wire");
3072 assert_eq!(decoded, rich_module(), "decode is the inverse of encode");
3073 let reverified = decoded.verify().expect("decoded module reverifies");
3074 assert_eq!(reverified.encode(), encoded, "round-trip is canonical");
3075 }
3076
3077 #[test]
3081 fn every_opcode_round_trips_on_the_wire() {
3082 let instructions = [
3083 Instruction::LoadConst {
3084 dst: Register::new(1),
3085 constant: ConstantId::new(2),
3086 },
3087 Instruction::Move {
3088 dst: Register::new(3),
3089 src: Register::new(4),
3090 },
3091 Instruction::Unary {
3092 dst: Register::new(5),
3093 op: UnaryOp::LogicalNot,
3094 operand: Register::new(6),
3095 },
3096 Instruction::Binary {
3097 dst: Register::new(7),
3098 op: BinaryOp::StrictEqual,
3099 left: Register::new(8),
3100 right: Register::new(9),
3101 },
3102 Instruction::CreateObject {
3103 dst: Register::new(10),
3104 },
3105 Instruction::CreateArray {
3106 dst: Register::new(11),
3107 },
3108 Instruction::CreateClosure {
3109 dst: Register::new(12),
3110 function: FunctionId::new(13),
3111 captures: Register::new(14),
3112 },
3113 Instruction::GetProperty {
3114 dst: Register::new(15),
3115 object: Register::new(16),
3116 key: Register::new(17),
3117 },
3118 Instruction::SetProperty {
3119 object: Register::new(18),
3120 key: Register::new(19),
3121 value: Register::new(20),
3122 },
3123 Instruction::DeleteProperty {
3124 dst: Register::new(21),
3125 object: Register::new(22),
3126 key: Register::new(23),
3127 },
3128 Instruction::DefineAccessor {
3129 object: Register::new(24),
3130 key: Register::new(25),
3131 accessor: Register::new(26),
3132 kind: AccessorKind::Setter,
3133 },
3134 Instruction::Call {
3135 dst: Register::new(27),
3136 callee: Register::new(28),
3137 this_value: Register::new(29),
3138 arguments: Register::new(30),
3139 },
3140 Instruction::Construct {
3141 dst: Register::new(31),
3142 callee: Register::new(32),
3143 arguments: Register::new(33),
3144 },
3145 Instruction::LoadGlobal {
3146 dst: Register::new(34),
3147 name: ConstantId::new(35),
3148 },
3149 Instruction::StoreGlobal {
3150 name: ConstantId::new(36),
3151 value: Register::new(37),
3152 },
3153 Instruction::TypeOfGlobal {
3154 dst: Register::new(38),
3155 name: ConstantId::new(39),
3156 },
3157 Instruction::LoadThis {
3158 dst: Register::new(40),
3159 },
3160 Instruction::LoadArguments {
3161 dst: Register::new(41),
3162 },
3163 Instruction::LoadNewTarget {
3164 dst: Register::new(42),
3165 },
3166 Instruction::ArrayPush {
3167 array: Register::new(43),
3168 value: Register::new(44),
3169 },
3170 Instruction::ArrayExtend {
3171 array: Register::new(45),
3172 iterable: Register::new(46),
3173 },
3174 Instruction::ObjectSpread {
3175 target: Register::new(47),
3176 source: Register::new(48),
3177 },
3178 Instruction::SetPrototype {
3179 object: Register::new(49),
3180 prototype: Register::new(50),
3181 },
3182 Instruction::CreatePrivateName {
3183 dst: Register::new(51),
3184 description: ConstantId::new(52),
3185 },
3186 Instruction::CreateRegExp {
3187 dst: Register::new(53),
3188 pattern: ConstantId::new(54),
3189 flags: ConstantId::new(55),
3190 },
3191 Instruction::GetIterator {
3192 dst: Register::new(56),
3193 src: Register::new(57),
3194 kind: IteratorKind::Async,
3195 },
3196 Instruction::IteratorNext {
3197 done: Register::new(58),
3198 value: Register::new(59),
3199 iterator: Register::new(60),
3200 },
3201 Instruction::Jump {
3202 target: Pc::new(61),
3203 },
3204 Instruction::JumpIfTrue {
3205 condition: Register::new(62),
3206 target: Pc::new(63),
3207 },
3208 Instruction::JumpIfFalse {
3209 condition: Register::new(64),
3210 target: Pc::new(65),
3211 },
3212 Instruction::Return {
3213 value: Register::new(66),
3214 },
3215 Instruction::Throw {
3216 value: Register::new(67),
3217 },
3218 Instruction::Suspend {
3219 dst: Register::new(68),
3220 src: Register::new(69),
3221 resume: Pc::new(70),
3222 },
3223 Instruction::Import {
3224 dst: Register::new(71),
3225 specifier: ConstantId::new(72),
3226 },
3227 Instruction::Export {
3228 name: ConstantId::new(73),
3229 src: Register::new(74),
3230 },
3231 Instruction::Halt,
3232 Instruction::CreateCell {
3233 dst: Register::new(75),
3234 },
3235 ];
3236 assert_eq!(instructions.len(), 37, "one case per opcode");
3237 let limits = DecodeLimits::default();
3238 for (opcode, instruction) in instructions.into_iter().enumerate() {
3239 let mut bytes = Vec::new();
3240 encode_instruction(instruction, &mut bytes);
3241 assert_eq!(
3242 bytes.first().copied(),
3243 Some(opcode as u8),
3244 "opcode tag is its table index"
3245 );
3246 let mut decoder = Decoder {
3247 bytes: &bytes,
3248 offset: 0,
3249 limits: &limits,
3250 total_instructions: 0,
3251 };
3252 let decoded = decoder.instruction().expect("opcode decodes");
3253 assert_eq!(decoded, instruction, "{instruction:?} round-trips");
3254 assert_eq!(decoder.offset, bytes.len(), "consumes exactly its bytes");
3255 }
3256 }
3257
3258 #[test]
3259 fn minimal_module_has_exact_canonical_wire() {
3260 let module = Module::new(
3261 vec![Constant::Int32(7)],
3262 vec![Function::new(
3263 None,
3264 0,
3265 0,
3266 1,
3267 flags(),
3268 vec![
3269 Instruction::LoadConst {
3270 dst: Register::new(0),
3271 constant: ConstantId::new(0),
3272 },
3273 Instruction::Return {
3274 value: Register::new(0),
3275 },
3276 ],
3277 Vec::new(),
3278 )],
3279 FunctionId::new(0),
3280 );
3281 let encoded = module.verify().expect("valid").encode();
3282 let mut expected = prefix();
3283 expected.extend_from_slice(&[
3284 1, 1, 7, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 30, 0, 0, ]);
3298 assert_eq!(encoded, expected);
3299 }
3300
3301 #[test]
3302 fn fields_beyond_127_scale_and_round_trip() {
3303 let constant_count: u32 = 200;
3305 let mut constants = Vec::new();
3306 for value in 0..constant_count {
3307 constants.push(Constant::Int32(value as i32));
3308 }
3309 let register_count: u32 = 200;
3310 let mut code = Vec::new();
3311 for register in 0..register_count {
3312 code.push(Instruction::LoadConst {
3313 dst: Register::new(register),
3314 constant: ConstantId::new(register % constant_count),
3315 });
3316 }
3317 code.push(Instruction::Return {
3318 value: Register::new(register_count - 1),
3319 });
3320 let module = Module::new(
3321 constants,
3322 vec![Function::new(
3323 None,
3324 0,
3325 0,
3326 register_count,
3327 flags(),
3328 code,
3329 Vec::new(),
3330 )],
3331 FunctionId::new(0),
3332 );
3333 let verified = module.clone().verify().expect("large module verifies");
3334 let encoded = verified.encode();
3335 assert!(
3337 (0..encoded.len().saturating_sub(1))
3338 .any(|i| encoded[i] == 0xc8 && encoded[i + 1] == 0x01),
3339 "constant count 200 must use a two-byte LEB128 group"
3340 );
3341 let decoded = decode(&encoded, &DecodeLimits::default()).expect("round trip");
3342 assert_eq!(decoded, module);
3343 assert_eq!(decoded.verify().expect("reverify").encode(), encoded,);
3344 }
3345
3346 #[test]
3349 fn calls_scale_past_fixed_window_via_arguments_array() {
3350 let mut code = vec![
3351 Instruction::CreateObject {
3352 dst: Register::new(0),
3353 }, Instruction::CreateObject {
3355 dst: Register::new(1),
3356 }, Instruction::CreateArray {
3358 dst: Register::new(2),
3359 }, ];
3361 for _ in 0..500 {
3364 code.push(Instruction::ArrayPush {
3365 array: Register::new(2),
3366 value: Register::new(1),
3367 });
3368 }
3369 code.push(Instruction::Call {
3370 dst: Register::new(3),
3371 callee: Register::new(0),
3372 this_value: Register::new(1),
3373 arguments: Register::new(2),
3374 });
3375 code.push(Instruction::Return {
3376 value: Register::new(3),
3377 });
3378 let module = Module::new(
3379 vec![],
3380 vec![Function::new(None, 0, 0, 4, flags(), code, vec![])],
3381 FunctionId::new(0),
3382 );
3383 let verified = module.clone().verify().expect("variadic call verifies");
3384 assert_eq!(
3385 decode(&verified.encode(), &DecodeLimits::default())
3386 .expect("round trip")
3387 .verify()
3388 .expect("reverify")
3389 .encode(),
3390 verified.encode()
3391 );
3392 }
3393
3394 fn decode_leb(bytes: &[u8]) -> Result<u32, DecodeError> {
3395 let limits = DecodeLimits::default();
3396 let mut decoder = Decoder {
3397 bytes,
3398 offset: 0,
3399 limits: &limits,
3400 total_instructions: 0,
3401 };
3402 decoder.leb128()
3403 }
3404
3405 #[test]
3406 fn leb128_accepts_only_canonical_encodings() {
3407 assert_eq!(decode_leb(&[0]), Ok(0));
3408 assert_eq!(decode_leb(&[1]), Ok(1));
3409 assert_eq!(decode_leb(&[127]), Ok(127));
3410 assert_eq!(decode_leb(&[0xc8, 0x01]), Ok(200));
3411 assert_eq!(decode_leb(&[0xff, 0xff, 0xff, 0xff, 0x0f]), Ok(u32::MAX));
3412
3413 assert_eq!(
3415 decode_leb(&[0x80, 0x00]),
3416 Err(DecodeError {
3417 offset: 0,
3418 kind: DecodeErrorKind::NonCanonicalInteger,
3419 })
3420 );
3421 assert_eq!(
3423 decode_leb(&[0x81, 0x00]),
3424 Err(DecodeError {
3425 offset: 0,
3426 kind: DecodeErrorKind::NonCanonicalInteger,
3427 })
3428 );
3429 assert_eq!(
3432 decode_leb(&[0x80]),
3433 Err(DecodeError {
3434 offset: 1,
3435 kind: DecodeErrorKind::UnexpectedEof,
3436 })
3437 );
3438 assert_eq!(
3440 decode_leb(&[0xff, 0xff, 0xff, 0xff, 0x1f]),
3441 Err(DecodeError {
3442 offset: 0,
3443 kind: DecodeErrorKind::IntegerOverflow,
3444 })
3445 );
3446 assert_eq!(
3447 decode_leb(&[0x80, 0x80, 0x80, 0x80, 0x80]),
3448 Err(DecodeError {
3449 offset: 0,
3450 kind: DecodeErrorKind::IntegerOverflow,
3451 })
3452 );
3453 }
3454
3455 #[test]
3456 fn decode_errors_report_the_first_bad_byte() {
3457 let mut bytes = prefix();
3458 bytes[3] ^= 1;
3459 assert_eq!(
3460 decode(&bytes, &DecodeLimits::default()),
3461 Err(DecodeError {
3462 offset: 3,
3463 kind: DecodeErrorKind::BadMagic {
3464 expected: MAGIC[3],
3465 actual: bytes[3],
3466 },
3467 })
3468 );
3469 assert_eq!(
3470 decode(&MAGIC[..4], &DecodeLimits::default()),
3471 Err(DecodeError {
3472 offset: 4,
3473 kind: DecodeErrorKind::UnexpectedEof,
3474 })
3475 );
3476 let mut bad_version = MAGIC.to_vec();
3477 bad_version.push(1);
3478 assert_eq!(
3479 decode(&bad_version, &DecodeLimits::default()),
3480 Err(DecodeError {
3481 offset: 8,
3482 kind: DecodeErrorKind::UnsupportedVersion { version: 1 },
3483 })
3484 );
3485 }
3486
3487 #[test]
3488 fn truncated_string_reports_payload_start() {
3489 let mut bytes = prefix();
3490 bytes.extend_from_slice(&[1, 2, 2, b'a', 0]);
3491
3492 assert_eq!(
3493 decode(&bytes, &DecodeLimits::default()),
3494 Err(DecodeError {
3495 offset: 12,
3496 kind: DecodeErrorKind::UnexpectedEof,
3497 })
3498 );
3499 }
3500
3501 #[test]
3502 fn decoder_checks_limits_before_allocation() {
3503 let mut bytes = prefix();
3504 write_u32(200, &mut bytes); let limits = DecodeLimits {
3506 max_constants: 128,
3507 ..DecodeLimits::default()
3508 };
3509 assert_eq!(
3510 decode(&bytes, &limits),
3511 Err(DecodeError {
3512 offset: prefix().len(),
3513 kind: DecodeErrorKind::LimitExceeded {
3514 field: "constant count",
3515 limit: 128,
3516 actual: 200,
3517 },
3518 })
3519 );
3520 }
3521
3522 #[test]
3523 fn decoder_rejects_invalid_bigint_utf8_without_recovery() {
3524 let mut bytes = prefix();
3525 write_u32(1, &mut bytes); bytes.push(7); write_u32(1, &mut bytes); bytes.push(0xff); assert_eq!(
3530 decode(&bytes, &DecodeLimits::default()),
3531 Err(DecodeError {
3532 offset: prefix().len() + 3,
3533 kind: DecodeErrorKind::InvalidUtf8,
3534 })
3535 );
3536 }
3537
3538 #[test]
3539 fn decoder_rejects_truncated_string_units() {
3540 let mut bytes = prefix();
3541 write_u32(1, &mut bytes);
3542 bytes.push(2);
3543 write_u32(2, &mut bytes);
3544 bytes.extend_from_slice(&0xD800_u16.to_le_bytes());
3545 assert!(matches!(
3546 decode(&bytes, &DecodeLimits::default()),
3547 Err(DecodeError {
3548 kind: DecodeErrorKind::UnexpectedEof,
3549 ..
3550 })
3551 ));
3552 }
3553
3554 #[test]
3555 fn decoder_rejects_string_over_unit_limit() {
3556 let mut bytes = prefix();
3557 write_u32(1, &mut bytes);
3558 bytes.push(2);
3559 write_u32(3, &mut bytes);
3560 let limits = DecodeLimits {
3561 max_string_units: 2,
3562 ..DecodeLimits::default()
3563 };
3564 assert!(matches!(
3565 decode(&bytes, &limits),
3566 Err(DecodeError {
3567 kind: DecodeErrorKind::LimitExceeded {
3568 field: "string unit count",
3569 limit: 2,
3570 actual: 3,
3571 },
3572 ..
3573 })
3574 ));
3575 }
3576
3577 #[test]
3578 fn string_constants_round_trip_lone_surrogates() {
3579 let encoded = Module::new(
3580 vec![Constant::String(EcmaString::from_units(&[
3581 0xD800, 0xDC00, 0xDFFF,
3582 ]))],
3583 vec![Function::new(
3584 None,
3585 0,
3586 0,
3587 1,
3588 flags(),
3589 vec![Instruction::Halt],
3590 Vec::new(),
3591 )],
3592 FunctionId::new(0),
3593 )
3594 .verify()
3595 .expect("lone surrogates are valid literal constants")
3596 .encode();
3597 let module = decode(&encoded, &DecodeLimits::default())
3598 .expect("valid UTF-16 units")
3599 .verify()
3600 .expect("the decoded module verifies");
3601 assert!(matches!(
3602 module.constants(),
3603 [Constant::String(value)] if value.as_units() == [0xD800, 0xDC00, 0xDFFF]
3604 ));
3605 assert_eq!(module.encode(), encoded);
3606 }
3607
3608 #[test]
3609 fn decoder_rejects_noncanonical_nan_bits() {
3610 let mut bytes = prefix();
3611 write_u32(1, &mut bytes);
3612 bytes.push(0); bytes.extend_from_slice(&0x7ff0_0000_0000_0001_u64.to_le_bytes());
3614 assert_eq!(
3615 decode(&bytes, &DecodeLimits::default()),
3616 Err(DecodeError {
3617 offset: prefix().len() + 2,
3618 kind: DecodeErrorKind::NonCanonicalNumber {
3619 bits: 0x7ff0_0000_0000_0001,
3620 },
3621 })
3622 );
3623 assert_eq!(
3624 NumberBits::from_bits(0xfff0_0000_0000_0001).bits(),
3625 CANONICAL_NAN_BITS
3626 );
3627 }
3628
3629 #[test]
3630 fn decoder_rejects_invalid_bigint_text() {
3631 for text in ["007", "-0", "", "-", "1a", "+1", "00"] {
3632 let mut bytes = prefix();
3633 write_u32(1, &mut bytes);
3634 bytes.push(7); write_text(text, &mut bytes);
3636 assert!(
3637 matches!(
3638 decode(&bytes, &DecodeLimits::default()),
3639 Err(DecodeError {
3640 kind: DecodeErrorKind::InvalidBigInt,
3641 ..
3642 })
3643 ),
3644 "expected {text:?} to be rejected"
3645 );
3646 }
3647 for text in ["0", "7", "-7", "1234567890123456789012345"] {
3649 assert!(BigIntLiteral::new(text.to_owned()).is_some(), "{text}");
3650 }
3651 }
3652
3653 fn one_function_bytes(body: &[u8]) -> Vec<u8> {
3656 let mut bytes = prefix();
3657 write_u32(0, &mut bytes); write_u32(1, &mut bytes); write_u32(0, &mut bytes); write_u32(0, &mut bytes); write_u32(0, &mut bytes); write_u32(0, &mut bytes); write_u32(1, &mut bytes); bytes.push(0); write_u32(1, &mut bytes); bytes.extend_from_slice(body);
3667 bytes
3668 }
3669
3670 #[test]
3671 fn decoder_rejects_unknown_tags_flags_and_operators() {
3672 let mut bad_constant = prefix();
3674 write_u32(1, &mut bad_constant);
3675 bad_constant.push(200);
3676 assert!(matches!(
3677 decode(&bad_constant, &DecodeLimits::default()),
3678 Err(DecodeError {
3679 kind: DecodeErrorKind::InvalidConstantTag { tag: 200 },
3680 ..
3681 })
3682 ));
3683
3684 let mut bad_flags = prefix();
3686 write_u32(0, &mut bad_flags); write_u32(1, &mut bad_flags); write_u32(0, &mut bad_flags); write_u32(0, &mut bad_flags); write_u32(0, &mut bad_flags); write_u32(0, &mut bad_flags); write_u32(1, &mut bad_flags); bad_flags.push(0b100); assert!(matches!(
3695 decode(&bad_flags, &DecodeLimits::default()),
3696 Err(DecodeError {
3697 kind: DecodeErrorKind::InvalidFunctionFlags { bits: 0b100 },
3698 ..
3699 })
3700 ));
3701
3702 assert!(matches!(
3704 decode(&one_function_bytes(&[250]), &DecodeLimits::default()),
3705 Err(DecodeError {
3706 kind: DecodeErrorKind::InvalidOpcode { opcode: 250 },
3707 ..
3708 })
3709 ));
3710 assert!(matches!(
3712 decode(
3713 &one_function_bytes(&[2, 0, 99, 0]),
3714 &DecodeLimits::default()
3715 ),
3716 Err(DecodeError {
3717 kind: DecodeErrorKind::InvalidUnaryOp { tag: 99 },
3718 ..
3719 })
3720 ));
3721 assert!(matches!(
3723 decode(
3724 &one_function_bytes(&[3, 0, 99, 0, 0]),
3725 &DecodeLimits::default()
3726 ),
3727 Err(DecodeError {
3728 kind: DecodeErrorKind::InvalidBinaryOp { tag: 99 },
3729 ..
3730 })
3731 ));
3732 assert!(matches!(
3734 decode(
3735 &one_function_bytes(&[25, 0, 0, 9]),
3736 &DecodeLimits::default()
3737 ),
3738 Err(DecodeError {
3739 kind: DecodeErrorKind::InvalidIteratorKind { tag: 9 },
3740 ..
3741 })
3742 ));
3743 assert!(matches!(
3745 decode(
3746 &one_function_bytes(&[10, 0, 0, 0, 9]),
3747 &DecodeLimits::default()
3748 ),
3749 Err(DecodeError {
3750 kind: DecodeErrorKind::InvalidAccessorKind { tag: 9 },
3751 ..
3752 })
3753 ));
3754 }
3755
3756 #[test]
3757 fn decoder_rejects_trailing_bytes() {
3758 let mut trailing = rich_module().verify().expect("valid").encode();
3759 trailing.push(0);
3760 assert!(matches!(
3761 decode(&trailing, &DecodeLimits::default()),
3762 Err(DecodeError {
3763 kind: DecodeErrorKind::TrailingBytes { count: 1 },
3764 ..
3765 })
3766 ));
3767 }
3768
3769 #[test]
3770 fn decode_is_total_over_hostile_bytes() {
3771 let valid = rich_module().verify().expect("valid").encode();
3774 for len in 0..=valid.len() {
3775 let _ = decode(&valid[..len], &DecodeLimits::default());
3776 }
3777 for seed in 0u16..=255 {
3778 let soup: Vec<u8> = (0..64).map(|i| (seed as u8).wrapping_mul(i + 1)).collect();
3779 let _ = decode(&soup, &DecodeLimits::default());
3780 }
3781 }
3782
3783 #[test]
3784 fn single_byte_mutations_change_decode_result() {
3785 let encoded = rich_module().verify().expect("valid").encode();
3786 let baseline = decode(&encoded, &DecodeLimits::default());
3787 let mut observed_difference = false;
3788 for index in 0..encoded.len() {
3789 let mut mutated = encoded.clone();
3790 mutated[index] = mutated[index].wrapping_add(1);
3791 if decode(&mutated, &DecodeLimits::default()) != baseline {
3792 observed_difference = true;
3793 }
3794 }
3795 assert!(
3796 observed_difference,
3797 "flipping bytes must be observable at the decode boundary"
3798 );
3799 }
3800
3801 #[test]
3802 fn verifier_rejects_empty_module_and_bad_entry() {
3803 assert_eq!(
3804 Module::new(vec![], vec![], FunctionId::new(0)).verify(),
3805 Err(module_error(VerifyErrorKind::EmptyModule))
3806 );
3807 let bad_entry = Module::new(
3808 vec![],
3809 vec![Function::new(
3810 None,
3811 0,
3812 0,
3813 0,
3814 flags(),
3815 vec![Instruction::Halt],
3816 vec![],
3817 )],
3818 FunctionId::new(1),
3819 );
3820 assert!(matches!(
3821 bad_entry.verify(),
3822 Err(VerifyError {
3823 kind: VerifyErrorKind::EntryFunctionOutOfBounds { .. },
3824 ..
3825 })
3826 ));
3827 }
3828
3829 #[test]
3830 fn verifier_rejects_bad_function_metadata() {
3831 let empty_function = Module::new(
3832 vec![],
3833 vec![Function::new(None, 0, 0, 0, flags(), vec![], vec![])],
3834 FunctionId::new(0),
3835 );
3836 assert!(matches!(
3837 empty_function.verify(),
3838 Err(VerifyError {
3839 kind: VerifyErrorKind::EmptyFunction,
3840 ..
3841 })
3842 ));
3843
3844 let too_many_params = Module::new(
3845 vec![],
3846 vec![Function::new(
3847 None,
3848 0,
3849 2,
3850 1,
3851 flags(),
3852 vec![Instruction::Halt],
3853 vec![],
3854 )],
3855 FunctionId::new(0),
3856 );
3857 assert!(matches!(
3858 too_many_params.verify(),
3859 Err(VerifyError {
3860 kind: VerifyErrorKind::ParameterCountExceedsRegisters { .. },
3861 ..
3862 })
3863 ));
3864
3865 let captures_and_params_overflow = Module::new(
3868 vec![],
3869 vec![Function::new(
3870 None,
3871 1,
3872 1,
3873 1,
3874 flags(),
3875 vec![Instruction::Halt],
3876 vec![],
3877 )],
3878 FunctionId::new(0),
3879 );
3880 assert!(matches!(
3881 captures_and_params_overflow.verify(),
3882 Err(VerifyError {
3883 kind: VerifyErrorKind::EntryRegistersExceedRegisterCount { .. },
3884 ..
3885 })
3886 ));
3887
3888 let bad_name = Module::new(
3889 vec![Constant::Int32(0)],
3890 vec![Function::new(
3891 Some(ConstantId::new(0)),
3892 0,
3893 0,
3894 0,
3895 flags(),
3896 vec![Instruction::Halt],
3897 vec![],
3898 )],
3899 FunctionId::new(0),
3900 );
3901 assert!(matches!(
3902 bad_name.verify(),
3903 Err(VerifyError {
3904 kind: VerifyErrorKind::FunctionNameNotString { .. },
3905 ..
3906 })
3907 ));
3908 }
3909
3910 #[test]
3911 fn verifier_rejects_out_of_bounds_references() {
3912 let bad_register = Module::new(
3913 vec![Constant::Int32(0)],
3914 vec![Function::new(
3915 None,
3916 0,
3917 0,
3918 1,
3919 flags(),
3920 vec![Instruction::LoadConst {
3921 dst: Register::new(1),
3922 constant: ConstantId::new(0),
3923 }],
3924 vec![],
3925 )],
3926 FunctionId::new(0),
3927 );
3928 assert!(matches!(
3929 bad_register.verify(),
3930 Err(VerifyError {
3931 kind: VerifyErrorKind::RegisterOutOfBounds { .. },
3932 ..
3933 })
3934 ));
3935
3936 let bad_constant = Module::new(
3937 vec![],
3938 vec![Function::new(
3939 None,
3940 0,
3941 0,
3942 1,
3943 flags(),
3944 vec![Instruction::LoadConst {
3945 dst: Register::new(0),
3946 constant: ConstantId::new(0),
3947 }],
3948 vec![],
3949 )],
3950 FunctionId::new(0),
3951 );
3952 assert!(matches!(
3953 bad_constant.verify(),
3954 Err(VerifyError {
3955 kind: VerifyErrorKind::ConstantOutOfBounds { .. },
3956 ..
3957 })
3958 ));
3959
3960 let bad_function_ref = Module::new(
3961 vec![],
3962 vec![Function::new(
3963 None,
3964 0,
3965 0,
3966 1,
3967 flags(),
3968 vec![
3969 Instruction::CreateArray {
3970 dst: Register::new(0),
3971 },
3972 Instruction::CreateClosure {
3973 dst: Register::new(0),
3974 function: FunctionId::new(5),
3975 captures: Register::new(0),
3976 },
3977 Instruction::Return {
3978 value: Register::new(0),
3979 },
3980 ],
3981 vec![],
3982 )],
3983 FunctionId::new(0),
3984 );
3985 assert!(matches!(
3986 bad_function_ref.verify(),
3987 Err(VerifyError {
3988 kind: VerifyErrorKind::FunctionReferenceOutOfBounds { .. },
3989 ..
3990 })
3991 ));
3992 }
3993
3994 #[test]
3997 fn verifier_requires_string_constants_for_named_refs() {
3998 let cases: Vec<(&str, Instruction)> = vec![
3999 (
4000 "LoadGlobal",
4001 Instruction::LoadGlobal {
4002 dst: Register::new(0),
4003 name: ConstantId::new(0),
4004 },
4005 ),
4006 (
4007 "TypeOfGlobal",
4008 Instruction::TypeOfGlobal {
4009 dst: Register::new(0),
4010 name: ConstantId::new(0),
4011 },
4012 ),
4013 (
4014 "CreatePrivateName",
4015 Instruction::CreatePrivateName {
4016 dst: Register::new(0),
4017 description: ConstantId::new(0),
4018 },
4019 ),
4020 (
4021 "CreateRegExp",
4022 Instruction::CreateRegExp {
4023 dst: Register::new(0),
4024 pattern: ConstantId::new(0),
4025 flags: ConstantId::new(0),
4026 },
4027 ),
4028 (
4029 "Import",
4030 Instruction::Import {
4031 dst: Register::new(0),
4032 specifier: ConstantId::new(0),
4033 },
4034 ),
4035 ];
4036 for (label, instruction) in cases {
4037 let module = Module::new(
4038 vec![Constant::Int32(0)], vec![Function::new(
4040 None,
4041 0,
4042 0,
4043 1,
4044 flags(),
4045 vec![
4046 instruction,
4047 Instruction::Return {
4048 value: Register::new(0),
4049 },
4050 ],
4051 vec![],
4052 )],
4053 FunctionId::new(0),
4054 );
4055 assert!(
4056 matches!(
4057 module.verify(),
4058 Err(VerifyError {
4059 kind: VerifyErrorKind::StringConstantExpected { .. },
4060 ..
4061 })
4062 ),
4063 "{label} must require a string constant"
4064 );
4065 }
4066
4067 let export = Module::new(
4069 vec![Constant::Int32(0)],
4070 vec![Function::new(
4071 None,
4072 0,
4073 0,
4074 1,
4075 flags(),
4076 vec![
4077 Instruction::CreateObject {
4078 dst: Register::new(0),
4079 },
4080 Instruction::Export {
4081 name: ConstantId::new(0),
4082 src: Register::new(0),
4083 },
4084 Instruction::Return {
4085 value: Register::new(0),
4086 },
4087 ],
4088 vec![],
4089 )],
4090 FunctionId::new(0),
4091 );
4092 assert!(matches!(
4093 export.verify(),
4094 Err(VerifyError {
4095 kind: VerifyErrorKind::StringConstantExpected { .. },
4096 ..
4097 })
4098 ));
4099 }
4100
4101 #[test]
4104 fn verifier_requires_capture_and_argument_registers_initialized() {
4105 let uninit_captures = Module::new(
4107 vec![],
4108 vec![Function::new(
4109 None,
4110 0,
4111 0,
4112 2,
4113 flags(),
4114 vec![
4115 Instruction::CreateClosure {
4116 dst: Register::new(1),
4117 function: FunctionId::new(0),
4118 captures: Register::new(0),
4119 },
4120 Instruction::Return {
4121 value: Register::new(1),
4122 },
4123 ],
4124 vec![],
4125 )],
4126 FunctionId::new(0),
4127 );
4128 assert_eq!(
4129 uninit_captures.verify(),
4130 Err(VerifyError {
4131 function: Some(FunctionId::new(0)),
4132 instruction: Some(Pc::new(0)),
4133 kind: VerifyErrorKind::ReadBeforeWrite {
4134 register: Register::new(0),
4135 },
4136 })
4137 );
4138
4139 let uninit_args = Module::new(
4141 vec![],
4142 vec![Function::new(
4143 None,
4144 0,
4145 0,
4146 4,
4147 flags(),
4148 vec![
4149 Instruction::CreateObject {
4150 dst: Register::new(0),
4151 },
4152 Instruction::CreateObject {
4153 dst: Register::new(1),
4154 },
4155 Instruction::Call {
4156 dst: Register::new(3),
4157 callee: Register::new(0),
4158 this_value: Register::new(1),
4159 arguments: Register::new(2),
4160 },
4161 Instruction::Return {
4162 value: Register::new(3),
4163 },
4164 ],
4165 vec![],
4166 )],
4167 FunctionId::new(0),
4168 );
4169 assert_eq!(
4170 uninit_args.verify(),
4171 Err(VerifyError {
4172 function: Some(FunctionId::new(0)),
4173 instruction: Some(Pc::new(2)),
4174 kind: VerifyErrorKind::ReadBeforeWrite {
4175 register: Register::new(2),
4176 },
4177 })
4178 );
4179 }
4180
4181 #[test]
4182 fn verifier_rejects_reachable_falloff() {
4183 let module = Module::new(
4184 vec![],
4185 vec![Function::new(
4186 None,
4187 0,
4188 0,
4189 1,
4190 flags(),
4191 vec![Instruction::CreateObject {
4193 dst: Register::new(0),
4194 }],
4195 vec![],
4196 )],
4197 FunctionId::new(0),
4198 );
4199 assert!(matches!(
4200 module.verify(),
4201 Err(VerifyError {
4202 kind: VerifyErrorKind::JumpOutOfBounds { target: 1, .. },
4203 ..
4204 })
4205 ));
4206 }
4207
4208 #[test]
4209 fn verifier_rejects_bad_jump_and_conditional_targets() {
4210 for instruction in [
4211 Instruction::Jump { target: Pc::new(9) },
4212 Instruction::JumpIfFalse {
4213 condition: Register::new(0),
4214 target: Pc::new(9),
4215 },
4216 ] {
4217 let module = Module::new(
4218 vec![],
4219 vec![Function::new(
4220 None,
4221 0,
4222 1, 1,
4224 flags(),
4225 vec![instruction],
4226 vec![],
4227 )],
4228 FunctionId::new(0),
4229 );
4230 assert!(matches!(
4231 module.verify(),
4232 Err(VerifyError {
4233 kind: VerifyErrorKind::JumpOutOfBounds { .. },
4234 ..
4235 })
4236 ));
4237 }
4238 }
4239
4240 #[test]
4241 fn verifier_rejects_read_before_write() {
4242 let module = Module::new(
4243 vec![],
4244 vec![Function::new(
4245 None,
4246 0,
4247 0,
4248 3,
4249 flags(),
4250 vec![
4251 Instruction::Binary {
4252 dst: Register::new(2),
4253 op: BinaryOp::Add,
4254 left: Register::new(0),
4255 right: Register::new(1),
4256 },
4257 Instruction::Return {
4258 value: Register::new(2),
4259 },
4260 ],
4261 vec![],
4262 )],
4263 FunctionId::new(0),
4264 );
4265 assert_eq!(
4266 module.verify(),
4267 Err(VerifyError {
4268 function: Some(FunctionId::new(0)),
4269 instruction: Some(Pc::new(0)),
4270 kind: VerifyErrorKind::ReadBeforeWrite {
4271 register: Register::new(0),
4272 },
4273 })
4274 );
4275 }
4276
4277 #[test]
4278 fn captures_and_parameters_are_initialized_on_entry() {
4279 let module = Module::new(
4282 vec![],
4283 vec![Function::new(
4284 None,
4285 1,
4286 2,
4287 4,
4288 flags(),
4289 vec![
4290 Instruction::Binary {
4291 dst: Register::new(3),
4292 op: BinaryOp::Add,
4293 left: Register::new(0), right: Register::new(2), },
4296 Instruction::Return {
4297 value: Register::new(1), },
4299 ],
4300 vec![],
4301 )],
4302 FunctionId::new(0),
4303 );
4304 let verified = module.verify().expect("captures and params initialized");
4305 let certificate = verified.certificate(FunctionId::new(0)).unwrap();
4306 assert_eq!(
4307 certificate.initialized_before(Pc::new(0), Register::new(0)),
4308 Some(true),
4309 "capture is initialized on entry"
4310 );
4311 assert_eq!(
4312 certificate.initialized_before(Pc::new(0), Register::new(2)),
4313 Some(true),
4314 "parameter is initialized on entry"
4315 );
4316 assert_eq!(
4317 certificate.initialized_before(Pc::new(0), Register::new(3)),
4318 Some(false),
4319 "a non-entry register is not initialized on entry"
4320 );
4321 }
4322
4323 #[test]
4326 fn iterator_next_initializes_both_written_registers() {
4327 let module = Module::new(
4328 vec![],
4329 vec![Function::new(
4330 None,
4331 0,
4332 0,
4333 4,
4334 flags(),
4335 vec![
4336 Instruction::CreateArray {
4337 dst: Register::new(0),
4338 },
4339 Instruction::GetIterator {
4340 dst: Register::new(1),
4341 src: Register::new(0),
4342 kind: IteratorKind::Sync,
4343 },
4344 Instruction::IteratorNext {
4345 done: Register::new(2),
4346 value: Register::new(3),
4347 iterator: Register::new(1),
4348 },
4349 Instruction::Binary {
4352 dst: Register::new(2),
4353 op: BinaryOp::StrictEqual,
4354 left: Register::new(2),
4355 right: Register::new(3),
4356 },
4357 Instruction::Return {
4358 value: Register::new(2),
4359 },
4360 ],
4361 vec![],
4362 )],
4363 FunctionId::new(0),
4364 );
4365 let verified = module.verify().expect("two-write dataflow verifies");
4366 let certificate = verified.certificate(FunctionId::new(0)).unwrap();
4367 assert_eq!(
4368 certificate.initialized_before(Pc::new(3), Register::new(2)),
4369 Some(true)
4370 );
4371 assert_eq!(
4372 certificate.initialized_before(Pc::new(3), Register::new(3)),
4373 Some(true)
4374 );
4375 }
4376
4377 #[test]
4378 fn catch_register_is_observable_in_handler() {
4379 let module = Module::new(
4382 vec![],
4383 vec![Function::new(
4384 None,
4385 0,
4386 0,
4387 1,
4388 flags(),
4389 vec![
4390 Instruction::CreateObject {
4391 dst: Register::new(0),
4392 },
4393 Instruction::Throw {
4394 value: Register::new(0),
4395 },
4396 Instruction::Return {
4397 value: Register::new(0),
4398 }, ],
4400 vec![ExceptionHandler {
4401 start: Pc::new(0),
4402 end: Pc::new(2),
4403 handler: Pc::new(2),
4404 catch_register: Register::new(0),
4405 }],
4406 )],
4407 FunctionId::new(0),
4408 );
4409 let verified = module
4410 .verify()
4411 .expect("catch register initialized on dispatch");
4412 let certificate = verified.certificate(FunctionId::new(0)).unwrap();
4413 assert_eq!(
4414 certificate.initialized_before(Pc::new(2), Register::new(0)),
4415 Some(true)
4416 );
4417 }
4418
4419 #[test]
4420 fn verifier_rejects_bad_handler_bounds_and_catch_register() {
4421 let bad_range = Module::new(
4422 vec![],
4423 vec![Function::new(
4424 None,
4425 0,
4426 0,
4427 1,
4428 flags(),
4429 vec![Instruction::Halt, Instruction::Halt],
4430 vec![ExceptionHandler {
4431 start: Pc::new(1),
4432 end: Pc::new(1), handler: Pc::new(0),
4434 catch_register: Register::new(0),
4435 }],
4436 )],
4437 FunctionId::new(0),
4438 );
4439 assert!(matches!(
4440 bad_range.verify(),
4441 Err(VerifyError {
4442 kind: VerifyErrorKind::InvalidHandlerBounds { .. },
4443 ..
4444 })
4445 ));
4446
4447 let bad_catch = Module::new(
4448 vec![],
4449 vec![Function::new(
4450 None,
4451 0,
4452 0,
4453 1,
4454 flags(),
4455 vec![Instruction::Halt, Instruction::Halt],
4456 vec![ExceptionHandler {
4457 start: Pc::new(0),
4458 end: Pc::new(2),
4459 handler: Pc::new(1),
4460 catch_register: Register::new(5), }],
4462 )],
4463 FunctionId::new(0),
4464 );
4465 assert!(matches!(
4466 bad_catch.verify(),
4467 Err(VerifyError {
4468 kind: VerifyErrorKind::HandlerCatchRegisterOutOfBounds { .. },
4469 ..
4470 })
4471 ));
4472 }
4473
4474 #[test]
4475 fn verifier_rejects_partially_overlapping_handlers() {
4476 let module = Module::new(
4477 vec![],
4478 vec![Function::new(
4479 None,
4480 0,
4481 0,
4482 1,
4483 flags(),
4484 vec![Instruction::Halt, Instruction::Halt, Instruction::Halt],
4485 vec![
4486 ExceptionHandler {
4487 start: Pc::new(0),
4488 end: Pc::new(2),
4489 handler: Pc::new(0),
4490 catch_register: Register::new(0),
4491 },
4492 ExceptionHandler {
4493 start: Pc::new(1),
4494 end: Pc::new(3),
4495 handler: Pc::new(2),
4496 catch_register: Register::new(0),
4497 },
4498 ],
4499 )],
4500 FunctionId::new(0),
4501 );
4502 assert!(matches!(
4503 module.verify(),
4504 Err(VerifyError {
4505 kind: VerifyErrorKind::HandlersPartiallyOverlap { left: 0, right: 1 },
4506 ..
4507 })
4508 ));
4509 }
4510
4511 #[test]
4512 fn verifier_accepts_disjoint_adjacent_and_nested_handlers() {
4513 let handler = |start, end, target| ExceptionHandler {
4517 start: Pc::new(start),
4518 end: Pc::new(end),
4519 handler: Pc::new(target),
4520 catch_register: Register::new(0),
4521 };
4522 let module = Module::new(
4523 vec![],
4524 vec![Function::new(
4525 None,
4526 0,
4527 0,
4528 1,
4529 flags(),
4530 vec![Instruction::Halt; 10],
4531 vec![
4532 handler(0, 10, 0),
4533 handler(0, 10, 0),
4534 handler(1, 4, 1),
4535 handler(4, 7, 4),
4536 handler(7, 10, 7),
4537 ],
4538 )],
4539 FunctionId::new(0),
4540 );
4541 assert!(module.verify().is_ok());
4542 }
4543
4544 #[test]
4545 fn verifier_rejects_crossing_handlers_with_original_indices() {
4546 let module = Module::new(
4549 vec![],
4550 vec![Function::new(
4551 None,
4552 0,
4553 0,
4554 1,
4555 flags(),
4556 vec![Instruction::Halt; 15],
4557 vec![
4558 ExceptionHandler {
4559 start: Pc::new(0),
4560 end: Pc::new(10),
4561 handler: Pc::new(0),
4562 catch_register: Register::new(0),
4563 },
4564 ExceptionHandler {
4565 start: Pc::new(5),
4566 end: Pc::new(15),
4567 handler: Pc::new(5),
4568 catch_register: Register::new(0),
4569 },
4570 ],
4571 )],
4572 FunctionId::new(0),
4573 );
4574 assert!(matches!(
4575 module.verify(),
4576 Err(VerifyError {
4577 kind: VerifyErrorKind::HandlersPartiallyOverlap { left: 0, right: 1 },
4578 ..
4579 })
4580 ));
4581 }
4582
4583 #[test]
4584 fn verifier_accepts_and_preserves_order_of_deeply_nested_handlers() {
4585 const DEPTH: u32 = 64;
4589 let mut handlers: Vec<ExceptionHandler> = (0..DEPTH)
4590 .map(|level| ExceptionHandler {
4591 start: Pc::new(level),
4592 end: Pc::new(DEPTH * 2 - level),
4593 handler: Pc::new(level),
4594 catch_register: Register::new(0),
4595 })
4596 .collect();
4597 handlers.reverse();
4598 let module = Module::new(
4599 vec![],
4600 vec![Function::new(
4601 None,
4602 0,
4603 0,
4604 1,
4605 flags(),
4606 vec![Instruction::Halt; (DEPTH * 2) as usize],
4607 handlers.clone(),
4608 )],
4609 FunctionId::new(0),
4610 );
4611 let verified = module.verify().expect("laminar nesting verifies");
4612 assert_eq!(verified.functions()[0].handlers(), handlers.as_slice());
4613 }
4614
4615 #[test]
4616 fn verifier_rejects_facts_work_above_cap() {
4617 let words_per_instruction = u64::from(MAX_REGISTERS) / 64;
4625 let over_cap = (MAX_VERIFIER_FACTS_WORDS / words_per_instruction) as usize + 1;
4626 let module = Module::new(
4627 vec![],
4628 vec![Function::new(
4629 None,
4630 0,
4631 0,
4632 MAX_REGISTERS,
4633 flags(),
4634 vec![Instruction::Halt; over_cap],
4635 vec![],
4636 )],
4637 FunctionId::new(0),
4638 );
4639 assert!(matches!(
4640 module.verify(),
4641 Err(VerifyError {
4642 kind: VerifyErrorKind::VerifierWorkLimitExceeded { .. },
4643 ..
4644 })
4645 ));
4646 }
4647
4648 #[test]
4649 fn verifier_rejects_hostile_near_max_work_before_allocating() {
4650 let module = Module::new(
4654 vec![],
4655 vec![Function::new(
4656 None,
4657 0,
4658 0,
4659 MAX_REGISTERS,
4660 flags(),
4661 vec![Instruction::Halt; MAX_REGISTERS as usize],
4662 vec![],
4663 )],
4664 FunctionId::new(0),
4665 );
4666 assert!(matches!(
4667 module.verify(),
4668 Err(VerifyError {
4669 kind: VerifyErrorKind::VerifierWorkLimitExceeded { .. },
4670 ..
4671 })
4672 ));
4673 }
4674
4675 #[test]
4676 fn verifier_accepts_loop_carried_facts_and_exposes_certificate() {
4677 let module = Module::new(
4678 vec![Constant::Int32(0)],
4679 vec![Function::new(
4680 None,
4681 0,
4682 0,
4683 2,
4684 flags(),
4685 vec![
4686 Instruction::LoadConst {
4687 dst: Register::new(0),
4688 constant: ConstantId::new(0),
4689 },
4690 Instruction::Binary {
4691 dst: Register::new(1),
4692 op: BinaryOp::Add,
4693 left: Register::new(0),
4694 right: Register::new(0),
4695 },
4696 Instruction::Jump { target: Pc::new(1) },
4697 ],
4698 vec![],
4699 )],
4700 FunctionId::new(0),
4701 );
4702 let verified = module.verify().expect("loop has a sound witness");
4703 let certificate = verified.certificate(FunctionId::new(0)).unwrap();
4704 assert_eq!(certificate.instruction_count(), 3);
4705 assert_eq!(
4706 certificate.initialized_before(Pc::new(1), Register::new(0)),
4707 Some(true)
4708 );
4709 }
4710
4711 #[test]
4712 fn certificate_queries_are_total_for_all_wrappers() {
4713 let verified = rich_module().verify().expect("valid");
4714 let certificate = verified.certificate(FunctionId::new(0)).unwrap();
4715 assert_eq!(
4717 certificate.initialized_before(Pc::new(0), Register::new(u32::MAX)),
4718 None
4719 );
4720 assert_eq!(
4722 certificate.initialized_before(Pc::new(u32::MAX), Register::new(0)),
4723 None
4724 );
4725 assert!(verified.certificate(FunctionId::new(9)).is_none());
4727 }
4728
4729 #[test]
4730 fn verification_bytes_counts_certificate_storage() {
4731 let instruction_count = 2usize;
4732 let register_count = 130u32;
4733 let module = Module::new(
4734 vec![],
4735 vec![Function::new(
4736 None,
4737 0,
4738 1,
4739 register_count,
4740 flags(),
4741 vec![
4742 Instruction::Move {
4743 dst: Register::new(129),
4744 src: Register::new(0),
4745 },
4746 Instruction::Return {
4747 value: Register::new(129),
4748 },
4749 ],
4750 vec![],
4751 )],
4752 FunctionId::new(0),
4753 )
4754 .verify()
4755 .expect("test module verifies");
4756 let words = RegisterSet::words_for(register_count);
4757 let expected = std::mem::size_of::<Certificate>()
4758 + instruction_count * std::mem::size_of::<RegisterSet>()
4759 + instruction_count * words * std::mem::size_of::<u64>();
4760
4761 assert_eq!(module.verification_bytes(), expected);
4762 }
4763
4764 #[test]
4765 fn compact_scalar_layouts_are_preserved() {
4766 assert_eq!(std::mem::size_of::<Register>(), 4);
4767 assert_eq!(std::mem::size_of::<Pc>(), 4);
4768 assert_eq!(std::mem::size_of::<NumberBits>(), 8);
4769 assert_eq!(std::mem::size_of::<FunctionFlags>(), 2);
4770 }
4771}