mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
numeric.c: raise TypeError for non-Integer bitwise operands
Integer#&, #| and #^ read the right-hand operand with mrb_integer() without checking its type. For a Float (or any non-Integer) this reads an unrelated union field and returns a garbage value instead of raising, as CRuby does. Raise TypeError via mrb_int_noconv() when the operand is not an Integer. Bigint operands are still handled before this point, and the shift operators keep coercing their width as before. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1352,6 +1352,7 @@ int_rev(mrb_state *mrb, mrb_value num)
|
||||
}
|
||||
|
||||
#define bit_op(x,y,op1,op2) do {\
|
||||
if (!mrb_integer_p(y)) mrb_int_noconv(mrb, y);\
|
||||
return mrb_int_value(mrb, (mrb_integer(x) op2 mrb_integer(y)));\
|
||||
} while(0)
|
||||
|
||||
|
||||
@@ -129,6 +129,18 @@ assert('Integer#^', '15.2.8.3.11') do
|
||||
assert_equal 6, 5 ^ 3
|
||||
end
|
||||
|
||||
assert('Integer bitwise ops reject non-Integer operands') do
|
||||
# A non-Integer operand has no bit pattern to combine, so &, |, ^ raise
|
||||
# TypeError instead of silently reading garbage (Float used to return a
|
||||
# bogus value via an unchecked union access).
|
||||
assert_raise(TypeError) { 5 & 5.0 }
|
||||
assert_raise(TypeError) { 5 | 5.0 }
|
||||
assert_raise(TypeError) { 5 ^ 5.0 }
|
||||
assert_raise(TypeError) { 5 | "3" }
|
||||
assert_raise(TypeError) { 5 & nil }
|
||||
assert_raise(TypeError) { 5 ^ :sym }
|
||||
end
|
||||
|
||||
assert('Integer#<<', '15.2.8.3.12') do
|
||||
# Left Shift by one
|
||||
# 00010111 (23)
|
||||
|
||||
Reference in New Issue
Block a user