rational_eq_b was using wrong struct fields (p1->numerator/denominator
which access i.num/i.den) for bigint-backed rationals that use b.num/b.den.
Also added missing MRB_TT_BIGINT case to prevent fallthrough to default
case which caused ping-pong recursion between Rational#== and Integer#==.
Co-authored-by: Claude <noreply@anthropic.com>
Shifting 1 left by MRB_INT_BIT-1 (e.g., 63 on 64-bit) bits into the sign
bit is undefined behavior. Change the overflow check from >= MRB_INT_BIT
to >= MRB_INT_BIT-1 to prevent this.
Co-authored-by: Claude <noreply@anthropic.com>
rational_new_b() expects both arguments to be bigints, but rational_new_f()
was passing an integer value for the numerator when the exponent was negative.
This caused a segfault in mrb_bint_reduce() which called RBIGINT() on the
integer value.
Test case: 5r**-92 (from oss-fuzz)
Co-authored-by: Claude <noreply@anthropic.com>
In rational_new_f(), the code performed ((mrb_int)1)<<exp without
checking if exp >= MRB_INT_BIT. Shifting by a value >= bit width
is undefined behavior in C.
Also fixed the negative exponent case which incorrectly used
deno >>= exp (right-shift by negative is UB). The correct logic
is deno <<= -exp to multiply denominator by 2^(-exp).
Both cases now check for overflow before shifting and fall back
to bigint operations when necessary.
Discovered via ClusterFuzz with input "92r**11".
Co-authored-by: Claude <noreply@anthropic.com>
Remove the static int_lshift function and directly call mrb_bint_lshift
at the only call site. This simplifies the code and avoids static
function name collision with src/numeric.c for future amalgamation
support.
Co-authored-by: Claude <noreply@anthropic.com>
Added complete call-seq documentation for all Rational methods in
mrblib/rational.rb (4 methods):
## Rational Class Methods:
- inspect: returns string representation for debugging with parentheses
format, showing the rational value in "(numerator/denominator)" form
- to_s: returns string representation in "numerator/denominator" format
for display and conversion purposes
- <=>: spaceship operator for comparison with other numeric types,
returns -1/0/+1 for less/equal/greater comparisons, enables Comparable
module functionality with proper nil handling for incomparable values
## Numeric Extension Methods:
- to_r: converts any numeric value to rational representation with
denominator of 1, part of the standard numeric conversion protocol
Co-authored-by: Atlassian Rovo Dev
The method introduced by #5979 causes a fault by swapping classes.
```console
% bin/mruby -e 'Method = Proc; p Object.method(:inspect)'
zsh: segmentation fault (core dumped) bin/mruby -e 'Method = Proc; p Object.method(:inspect)'
```
After applying this patch, a `TypeError` exception will be raised.
```console
% bin/mruby -e 'Method = Proc; p Object.method(:inspect)'
trace (most recent call last):
[1] -e:1
-e:1:in method: allocation failure of Proc (TypeError)
```
However, if the `mrb_vtype` is the same object, the same care must still be taken as before.
```console
% bin/mruby -e 'Method = Binding; p method(:puts).eval("12345")'
trace (most recent call last):
[1] -e:1
-e:1:in eval: wrong argument type nil (expected Proc) (TypeError)
```
Calling `Class#allocate` with `UnboundMethod#bind_call` usually succeeds without problems.
If this behavior does not make us happy, we can now prohibit it with `MRB_SET_INSTANCE_TT(klass, MRB_TT_UNDEF)`.
At the same time, it applies to the `Binding`, `Complex`, `Data`, `Float`, `Integer`, `Method`, `Rational` and `UnboundMethod` classes.