Example #1
0
    def deserialize_uleb128_as_u32(self) -> int:
        value = 0
        for shift in range(0, 32, 7):
            byte = int.from_bytes(self.read(1), "little", signed=False)
            digit = byte & 0x7F
            value |= digit << shift
            if value > MAX_U32:
                raise st.DeserializationError(
                    "Overflow while parsing uleb128-encoded uint32 value")
            if digit == byte:
                if shift > 0 and digit == 0:
                    raise st.DeserializationError(
                        "Invalid uleb128 number (unexpected zero digit)")
                return value

        raise st.DeserializationError(
            "Overflow while parsing uleb128-encoded uint32 value")
 def deserialize_bool(self) -> bool:
     b = int.from_bytes(self.read(1), byteorder="little", signed=False)
     if b == 0:
         return False
     elif b == 1:
         return True
     else:
         raise st.DeserializationError("Unexpected boolean value:", b)
Example #3
0
 def check_that_key_slices_are_increasing(self, slice1: typing.Tuple[int,
                                                                     int],
                                          slice2: typing.Tuple[int, int]):
     key1 = bytes(self.input.getbuffer()[slice1[0]:slice1[1]])
     key2 = bytes(self.input.getbuffer()[slice2[0]:slice2[1]])
     if key1 >= key2:
         raise st.DeserializationError(
             "Serialized keys in a map must be ordered by increasing lexicographic order"
         )
    def deserialize_any(self, obj_type) -> typing.Any:
        if obj_type in self.primitive_type_deserializer:
            return self.primitive_type_deserializer[obj_type]()

        elif hasattr(obj_type, "__origin__"):  # Generic type
            types = getattr(obj_type, "__args__")
            if getattr(obj_type, "__origin__") == collections.abc.Sequence:  # Sequence
                assert len(types) == 1
                item_type = types[0]
                length = self.deserialize_len()
                result = []
                for i in range(0, length):
                    item = self.deserialize_any(item_type)
                    result.append(item)

                return result

            elif getattr(obj_type, "__origin__") == tuple:  # Tuple
                result = []
                for i in range(len(types)):
                    item = self.deserialize_any(types[i])
                    result.append(item)
                return tuple(result)

            elif getattr(obj_type, "__origin__") == typing.Union:  # Option
                assert len(types) == 2 and types[1] == type(None)
                tag = int.from_bytes(self.read(1), byteorder="little", signed=False)
                if tag == 0:
                    return None
                elif tag == 1:
                    return self.deserialize_any(types[0])
                else:
                    raise st.DeserializationError("Wrong tag for Option value")

            elif getattr(obj_type, "__origin__") == dict:  # Map
                assert len(types) == 2
                length = self.deserialize_len()
                result = dict()
                previous_key_slice = None
                for i in range(0, length):
                    key_start = self.get_buffer_offset()
                    key = self.deserialize_any(types[0])
                    key_end = self.get_buffer_offset()
                    value = self.deserialize_any(types[1])

                    key_slice = (key_start, key_end)
                    if previous_key_slice is not None:
                        self.check_that_key_slices_are_increasing(
                            previous_key_slice, key_slice
                        )
                    previous_key_slice = key_slice

                    result[key] = value

                return result

            else:
                raise st.DeserializationError("Unexpected type", obj_type)

        else:
            # handle structs
            if dataclasses.is_dataclass(obj_type):
                values = []
                fields = dataclasses.fields(obj_type)
                typing_hints = get_type_hints(obj_type)
                self.increase_container_depth()
                for field in fields:
                    field_type = typing_hints[field.name]
                    field_value = self.deserialize_any(field_type)
                    values.append(field_value)
                self.decrease_container_depth()
                return obj_type(*values)

            # handle variant
            elif hasattr(obj_type, "VARIANTS"):
                variant_index = self.deserialize_variant_index()
                if variant_index not in range(len(obj_type.VARIANTS)):
                    raise st.DeserializationError(
                        "Unexpected variant index", variant_index
                    )
                new_type = obj_type.VARIANTS[variant_index]
                return self.deserialize_any(new_type)

            else:
                raise st.DeserializationError("Unexpected type", obj_type)
 def increase_container_depth(self):
     if self.container_depth_budget is not None:
         if self.container_depth_budget == 0:
             raise st.DeserializationError("Exceeded maximum container depth")
         self.container_depth_budget -= 1
 def deserialize_str(self) -> str:
     content = self.deserialize_bytes()
     try:
         return content.decode()
     except UnicodeDecodeError:
         raise st.DeserializationError("Invalid unicode string:", content)
 def read(self, length: int) -> bytes:
     value = self.input.read(length)
     if value is None or len(value) < length:
         raise st.DeserializationError("Input is too short")
     return value
Example #8
0
 def deserialize_len(self) -> int:
     value = int.from_bytes(self.read(8), byteorder="little", signed=False)
     if value > MAX_LENGTH:
         raise st.DeserializationError("Length exceeds the maximum supported value.")
     return value
Example #9
0
 def deserialize_len(self) -> int:
     value = self.deserialize_uleb128_as_u32()
     if value > MAX_LENGTH:
         raise st.DeserializationError(
             "Length exceeds the maximum supported value.")
     return value