From cd1ecb3f78758b8d037d1b95177a558cf10cae92 Mon Sep 17 00:00:00 2001 From: Shubham Padkonde Date: Fri, 2 Oct 2026 14:58:24 +0530 Subject: [PATCH] Fix byte-length validation for memoryviews --- stone/backends/python_rsrc/stone_validators.py | 9 +++++---- test/test_python_gen.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/stone/backends/python_rsrc/stone_validators.py b/stone/backends/python_rsrc/stone_validators.py index 5b1e2276..0cb1653b 100644 --- a/stone/backends/python_rsrc/stone_validators.py +++ b/stone/backends/python_rsrc/stone_validators.py @@ -370,12 +370,13 @@ def validate(self, val): if not isinstance(val, _binary_types): raise ValidationError("expected bytes type, got %s" % generic_type_name(val)) - elif self.max_length is not None and len(val) > self.max_length: + length = val.nbytes if isinstance(val, memoryview) else len(val) + if self.max_length is not None and length > self.max_length: raise ValidationError("'%s' must have at most %d bytes, got %d" - % (get_value_string(val), self.max_length, len(val))) - elif self.min_length is not None and len(val) < self.min_length: + % (get_value_string(val), self.max_length, length)) + elif self.min_length is not None and length < self.min_length: raise ValidationError("'%s' has fewer than %d bytes, got %d" - % (get_value_string(val), self.min_length, len(val))) + % (get_value_string(val), self.min_length, length)) return val diff --git a/test/test_python_gen.py b/test/test_python_gen.py index 44ed336b..390b3826 100755 --- a/test/test_python_gen.py +++ b/test/test_python_gen.py @@ -117,6 +117,16 @@ def test_bytes_validator(self): # Passes b.validate(b'\x00') + def test_bytes_validator_memoryview_length(self): + value = memoryview(b'abcdefgh').cast('I') + self.assertIs(bv.Bytes(min_length=8, max_length=8).validate(value), value) + with self.assertRaisesRegex(bv.ValidationError, 'at most 7 bytes, got 8'): + bv.Bytes(max_length=7).validate(value) + + def test_bytes_validator_multidimensional_memoryview(self): + value = memoryview(b'abcdefgh').cast('B', shape=[2, 4]) + self.assertIs(bv.Bytes(min_length=8, max_length=8).validate(value), value) + def test_timestamp_validator(self): class UTC(datetime.tzinfo): def utcoffset(self, dt): # pylint: disable=unused-argument,useless-suppression