Commit e4ce4826 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Make the same fixes for float, and run into the same issue

float.__new__(cls) can return something that is not an instance of cls

Disable rewriting of float.__new__ and int.__new__ in this changeset
parent ed4536df
......@@ -544,41 +544,25 @@ std::string floatFmt(double x, int precision, char code) {
return std::string(buf, n);
}
Box* floatNew(BoxedClass* _cls, Box* a) {
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "float.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (!isSubclass(cls, float_cls))
raiseExcHelper(TypeError, "float.__new__(%s): %s is not a subtype of float", getNameOfClass(cls)->c_str(),
getNameOfClass(cls)->c_str());
// Note: "a->cls == cls" is not a strong enough condition to let us
// reuse the argument:
if (cls == float_cls && a->cls == float_cls)
return a;
assert(cls->tp_basicsize >= sizeof(BoxedFloat));
void* mem = gc_alloc(cls->tp_basicsize, gc::GCKind::PYTHON);
BoxedFloat* rtn = ::new (mem) BoxedFloat(cls, 0);
initUserAttrs(rtn, cls);
BoxedFloat* _floatNew(Box* a) {
if (a->cls == float_cls) {
rtn->d = static_cast<BoxedFloat*>(a)->d;
return static_cast<BoxedFloat*>(a);
} else if (isSubclass(a->cls, float_cls)) {
return new BoxedFloat(float_cls, static_cast<BoxedFloat*>(a)->d);
} else if (isSubclass(a->cls, int_cls)) {
rtn->d = static_cast<BoxedInt*>(a)->n;
return new BoxedFloat(float_cls, static_cast<BoxedInt*>(a)->n);
} else if (a->cls == str_cls) {
const std::string& s = static_cast<BoxedString*>(a)->s;
if (s == "nan")
return boxFloat(NAN);
return new BoxedFloat(float_cls, NAN);
if (s == "-nan")
return boxFloat(-NAN);
return new BoxedFloat(float_cls, -NAN);
if (s == "inf")
return boxFloat(INFINITY);
return new BoxedFloat(float_cls, INFINITY);
if (s == "-inf")
return boxFloat(-INFINITY);
return new BoxedFloat(float_cls, -INFINITY);
rtn->d = strtod(s.c_str(), NULL);
return new BoxedFloat(float_cls, strtod(s.c_str(), NULL));
} else {
static const std::string float_str("__float__");
Box* r = callattr(a, &float_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = true }),
......@@ -593,9 +577,31 @@ Box* floatNew(BoxedClass* _cls, Box* a) {
if (!isSubclass(r->cls, float_cls)) {
raiseExcHelper(TypeError, "__float__ returned non-float (type %s)", r->cls->tp_name);
}
rtn->d = static_cast<BoxedFloat*>(r)->d;
return static_cast<BoxedFloat*>(r);
}
}
Box* floatNew(BoxedClass* _cls, Box* a) {
if (!isSubclass(_cls->cls, type_cls))
raiseExcHelper(TypeError, "float.__new__(X): X is not a type object (%s)", getTypeName(_cls)->c_str());
BoxedClass* cls = static_cast<BoxedClass*>(_cls);
if (!isSubclass(cls, float_cls))
raiseExcHelper(TypeError, "float.__new__(%s): %s is not a subtype of float", getNameOfClass(cls)->c_str(),
getNameOfClass(cls)->c_str());
if (cls == float_cls)
return _floatNew(a);
BoxedFloat* f = _floatNew(a);
assert(cls->tp_basicsize >= sizeof(BoxedFloat));
void* mem = gc_alloc(cls->tp_basicsize, gc::GCKind::PYTHON);
BoxedFloat* rtn = ::new (mem) BoxedFloat(cls, 0);
initUserAttrs(rtn, cls);
rtn->d = f->d;
return rtn;
}
......
......@@ -3458,7 +3458,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
allowable_news.push_back(object_new);
for (BoxedClass* allowed_cls : { int_cls, xrange_cls, float_cls, long_cls }) {
for (BoxedClass* allowed_cls : { xrange_cls, long_cls }) {
auto new_obj = typeLookup(allowed_cls, _new_str, NULL);
gc::registerPermanentRoot(new_obj);
allowable_news.push_back(new_obj);
......
......@@ -5,3 +5,32 @@ print f
print float(2)
# print f - 2
class F(float):
def __init__(self, *args):
print "F.__init__, %d args" % len(args)
f = F(1)
print f is float(f)
print type(float(f))
print float(f)
class D(object):
def __init__(self, d):
self.d = d
def __float__(self):
return self.d
for a in (1.0, D(2.0), F(), D(F())):
f = float(a)
print f, type(f)
f = float.__new__(F, a)
print f, type(f)
print type(float(D(F())))
class F2(float):
pass
print type(F2(D(F())))
......@@ -45,3 +45,5 @@ print type(x)
x = I(D(C()))
print type(x)
print type(int(C()))
......@@ -80,7 +80,7 @@ def get_expected_output(fn):
if cache_mtime > os.stat(fn).st_mtime and cache_mtime > get_extmodule_mtime():
try:
return cPickle.load(open(cache_fn))
except EOFError:
except (EOFError, ValueError):
pass
# TODO don't suppress warnings globally:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment