mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Reject extra positional arguments to float() (#8509)
* Reject extra positional arguments to float()
PyFloat::slot_new's exact-float fast path tested args.args.first(), which
succeeds for any number of positional arguments, so float(1.5, True)
returned the first one and never reached args.bind(vm). CPython's clinic
generated float_new runs _PyArg_CheckPositional("float", nargs, 0, 1)
before it fetches the first argument.
Add args.args.len() == 1 to the condition, as PyInt::slot_new,
PyStr::slot_new and PyComplex::slot_new already do; the extra argument
then falls through to args.bind(vm) and raises TypeError.
Assisted-by: Claude Code:claude-opus-5
* Bind float() arguments before the fast path
The exact-float fast path repeated float()'s argument count inline, which
duplicates what FromArgs::arity already knows. Bind first and match on the
resulting OptionalArg instead, so the positional and keyword rules stay in
one place and the bound value is reused by py_new.
Assisted-by: Claude Code:claude-opus-5
This commit is contained in:
1 parent
6cfa079950
commit
7b58a8980d
2 files changed
+14
-3
No files matched your search
@@ -176,16 +176,18 @@ impl Constructor for PyFloat {
|
||||
type Args = OptionalArg<PyObjectRef>;
|
||||
|
||||
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// Bind before the fast path so FromArgs::arity decides how many arguments
|
||||
// are acceptable, rather than a count repeated here.
|
||||
let arg: Self::Args = args.bind(vm)?;
|
||||
|
||||
// Optimization: return exact float as-is
|
||||
if cls.is(vm.ctx.types.float_type)
|
||||
&& args.kwargs.is_empty()
|
||||
&& let Some(first) = args.args.first()
|
||||
&& let OptionalArg::Present(first) = &arg
|
||||
&& first.class().is(vm.ctx.types.float_type)
|
||||
{
|
||||
return Ok(first.clone());
|
||||
}
|
||||
|
||||
let arg: Self::Args = args.bind(vm)?;
|
||||
let payload = Self::py_new(&cls, arg, vm)?;
|
||||
payload.into_ref_with_type(vm, cls).map(Into::into)
|
||||
}
|
||||
|
||||
@@ -561,3 +561,12 @@ assert str(161852602146008.12) == "161852602146008.12"
|
||||
assert repr(1.5) == "1.5"
|
||||
assert repr(0.1) == "0.1"
|
||||
assert repr(100.0) == "100.0"
|
||||
|
||||
|
||||
# float() takes at most one positional argument; the exact-float fast path
|
||||
# must not let extra ones through.
|
||||
assert_raises(TypeError, float, 1.5, True)
|
||||
assert_raises(TypeError, float, 1.5, 2, 3)
|
||||
assert_raises(TypeError, float, "1.5", 2)
|
||||
assert float(1.5) == 1.5
|
||||
assert float() == 0.0
|
||||
Reference in new issue
Block a user