Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Lib/test/test_memoryview.py
Original file line number Diff line number Diff line change
Expand Up @@ -620,9 +620,21 @@ def check_equal(view, is_equal):
m = memoryview(a.tobytes()).cast('n')
check_equal(m, True)

# Test '?' format
# Test '?' format (keep all the checks below for UBSan)
m = memoryview(b'\0\1\2').cast('?')
check_equal(m, True)
# m1a and m1b are equivalent to [False, True, False]
Comment thread
picnixz marked this conversation as resolved.
Outdated
m1a = memoryview(b'\0\2\0').cast('?')
self.assertEqual(m1a.tolist(), [False, True, False])
m1b = memoryview(b'\0\4\0').cast('?')
self.assertEqual(m1b.tolist(), [False, True, False])
self.assertEqual(m1a, m1b)
# m1a and m1b are equivalent to [True, True, True]
m2a = memoryview(b'\1\3\5').cast('?')
self.assertEqual(m2a.tolist(), [True, True, True])
m2b = memoryview(b'\2\4\6').cast('?')
self.assertEqual(m2b.tolist(), [True, True, True])
self.assertEqual(m2a, m2b)

# Test float formats
for float_format in 'fd':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fix an undefined behavior in :class:`memoryview` when using the native
boolean format (``?``) in :meth:`~memoryview.cast`. Previously, calling
Comment thread
picnixz marked this conversation as resolved.
Outdated
``memoryview(b).cast("?").tolist()`` incorrectly returned ``[False]``
instead of ``[True]`` for any even byte *b*. Patch by Bénédikt Tran.
7 changes: 5 additions & 2 deletions Objects/memoryobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,9 @@ fix_error_int(const char *fmt)
return -1;
}

// Return 0 if PTR represents "false", and 1 otherwise.
Comment thread
picnixz marked this conversation as resolved.
Outdated
#define UNPACK_TO_BOOL(PTR) (memcmp((PTR), &(_Bool){0}, sizeof(_Bool)) != 0)
Comment thread
picnixz marked this conversation as resolved.
Outdated

/* Accept integer objects or objects with an __index__() method. */
static long
pylong_as_ld(PyObject *item)
Expand Down Expand Up @@ -1811,7 +1814,7 @@ unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt)
case 'l': UNPACK_SINGLE(ld, ptr, long); goto convert_ld;

/* boolean */
case '?': UNPACK_SINGLE(ld, ptr, _Bool); goto convert_bool;
case '?': ld = UNPACK_TO_BOOL(ptr); goto convert_bool;

/* unsigned integers */
case 'H': UNPACK_SINGLE(lu, ptr, unsigned short); goto convert_lu;
Expand Down Expand Up @@ -3029,7 +3032,7 @@ unpack_cmp(const char *p, const char *q, char fmt,
case 'l': CMP_SINGLE(p, q, long); return equal;

/* boolean */
case '?': CMP_SINGLE(p, q, _Bool); return equal;
case '?': return UNPACK_TO_BOOL(p) == UNPACK_TO_BOOL(q);

/* unsigned integers */
case 'H': CMP_SINGLE(p, q, unsigned short); return equal;
Expand Down
3 changes: 0 additions & 3 deletions Tools/ubsan/suppressions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
# Objects/object.c:97:5: runtime error: member access within null pointer of type 'PyThreadState' (aka 'struct _ts')
null:Objects/object.c

# Objects/memoryobject.c:3032:15: runtime error: load of value 2, which is not a valid value for type 'bool'
bool:Objects/memoryobject.c

# Modules/_ctypes/cfield.c:644:1: runtime error: left shift of 1 by 63 places cannot be represented in type 'int64_t' (aka 'long')
shift-base:Modules/_ctypes/cfield.c

Expand Down
Loading