diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 686db459eff5b..107d2862c1256 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -592,14 +592,14 @@ static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ /* Read partial prefix byte */ if (pos != 0) { size_t num_bits = 8 - pos; - mask = ((1U << num_bits) - 1U) << pos; + mask = (1U << num_bits) - 1U; val = (*p++ >> pos) & mask; insert_pos += num_bits; } /* Read full bytes */ while (p < last_p) { - val |= *p++ << insert_pos; + val |= (uint64_t) *p++ << insert_pos; insert_pos += 8; } @@ -607,7 +607,7 @@ static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ if (p == last_p) { size_t num_bits = last_bit % 8 + 1; mask = (1U << num_bits) - 1U; - val |= (*p & mask) << insert_pos; + val |= (uint64_t) (*p & mask) << insert_pos; } return val; diff --git a/ext/ffi/tests/gh10403.phpt b/ext/ffi/tests/gh10403.phpt new file mode 100644 index 0000000000000..6e422c438fdf6 --- /dev/null +++ b/ext/ffi/tests/gh10403.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-10403: Fix incorrect bitshifting and masking in ffi bitfield +--EXTENSIONS-- +ffi +--SKIPIF-- + +--FILE-- +new('struct MyStruct'); +$test_struct->x = 1023; +$test_values = [0x3fafbfcfdfefff, 0x01020304050607, 0, 0x3fffffffffffff, 0x2ffffffffffff5]; +foreach ($test_values as $test_value) { + $test_struct->y = $test_value; + var_dump($test_struct->y === $test_value); +} +var_dump($test_struct->x); +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +int(1023)