Commit d092b31e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add a ReturnConvention for getattrs that can C++ throw

Otherwise callers have no way of knowing if an exception might
occur in the rewritten code, and they'd have to conservatively
not rewrite those cases (such as 3-arg getattr).

Well, previously getattr() wasn't doing that, so it would rewrite
itself correctly for a descriptor that is not throwing now, but would
start throwing later (those exceptions would get propagated instead
of being caught by getattr).
parent 2e2456b3
...@@ -1013,6 +1013,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1013,6 +1013,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
return res; return res;
} else if (return_convention == ReturnConvention::NO_RETURN) { } else if (return_convention == ReturnConvention::NO_RETURN) {
assert(!res); assert(!res);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
rewrite_args = NULL;
} else if (return_convention == ReturnConvention::CAPI_RETURN } else if (return_convention == ReturnConvention::CAPI_RETURN
|| return_convention == ReturnConvention::NOEXC_POSSIBLE) { || return_convention == ReturnConvention::NOEXC_POSSIBLE) {
// If we get a CAPI return, we probably did a function call, and these guards // If we get a CAPI return, we probably did a function call, and these guards
......
...@@ -576,8 +576,17 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -576,8 +576,17 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
std::tie(r_rtn, return_convention) = grewrite_args.getReturn(); std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE: // Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN) if (return_convention == ReturnConvention::NO_RETURN) {
return_convention = ReturnConvention::NOEXC_POSSIBLE;
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
if (default_value)
rewrite_args = NULL;
}
assert(!rewrite_args || return_convention == ReturnConvention::NOEXC_POSSIBLE
|| return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::CAPI_RETURN
|| (default_value == NULL && return_convention == ReturnConvention::MAYBE_EXC));
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str); rtn = getattrInternal<CAPI>(obj, str);
...@@ -687,8 +696,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -687,8 +696,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
std::tie(r_rtn, return_convention) = grewrite_args.getReturn(); std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE: // Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN) if (return_convention == ReturnConvention::NO_RETURN) {
return_convention = ReturnConvention::NOEXC_POSSIBLE;
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
} else if (return_convention == ReturnConvention::MAYBE_EXC) {
rewrite_args = NULL;
}
assert(!rewrite_args || return_convention == ReturnConvention::NOEXC_POSSIBLE
|| return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::CAPI_RETURN);
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str); rtn = getattrInternal<CAPI>(obj, str);
......
...@@ -1470,7 +1470,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1470,7 +1470,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
if (!crewrite_args.out_success) { if (!crewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
rewrite_args->setReturn(crewrite_args.out_rtn, ReturnConvention::HAS_RETURN); rewrite_args->setReturn(crewrite_args.out_rtn, ReturnConvention::MAYBE_EXC);
} }
return rtn; return rtn;
} }
...@@ -1498,6 +1498,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1498,6 +1498,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
rewrite_args = NULL; rewrite_args = NULL;
} }
Box* rtn = getset_descr->get(obj, getset_descr->closure);
if (rewrite_args) { if (rewrite_args) {
// hmm, maybe we should write assembly which can look up the function address and call any function // hmm, maybe we should write assembly which can look up the function address and call any function
r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, get), (intptr_t)getset_descr->get); r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, get), (intptr_t)getset_descr->get);
...@@ -1507,10 +1509,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1507,10 +1509,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
/* has_side_effects */ true, (void*)getset_descr->get, rewrite_args->obj, r_closure); /* has_side_effects */ true, (void*)getset_descr->get, rewrite_args->obj, r_closure);
rewrite_args->setReturn(r_rtn, descr->cls == capi_getset_cls ? ReturnConvention::CAPI_RETURN rewrite_args->setReturn(r_rtn, descr->cls == capi_getset_cls ? ReturnConvention::CAPI_RETURN
: ReturnConvention::HAS_RETURN); : ReturnConvention::MAYBE_EXC);
} }
return rtn;
return getset_descr->get(obj, getset_descr->closure);
} }
return NULL; return NULL;
...@@ -1693,7 +1694,12 @@ extern "C" Box* getclsattr(Box* obj, BoxedString* attr) { ...@@ -1693,7 +1694,12 @@ extern "C" Box* getclsattr(Box* obj, BoxedString* attr) {
gotten = getclsattrInternal<REWRITABLE>(obj, attr, &rewrite_args); gotten = getclsattrInternal<REWRITABLE>(obj, attr, &rewrite_args);
if (rewrite_args.isSuccessful() && gotten) { if (rewrite_args.isSuccessful() && gotten) {
RewriterVar* r_rtn = rewrite_args.getReturn(ReturnConvention::HAS_RETURN); RewriterVar* r_rtn;
ReturnConvention return_convention;
std::tie(r_rtn, return_convention) = rewrite_args.getReturn();
assert(return_convention == ReturnConvention::HAS_RETURN
|| return_convention == ReturnConvention::MAYBE_EXC);
rewriter->commitReturning(r_rtn); rewriter->commitReturning(r_rtn);
} }
#endif #endif
......
...@@ -49,6 +49,7 @@ enum class ReturnConvention { ...@@ -49,6 +49,7 @@ enum class ReturnConvention {
NO_RETURN, NO_RETURN,
CAPI_RETURN, CAPI_RETURN,
NOEXC_POSSIBLE, NOEXC_POSSIBLE,
MAYBE_EXC,
}; };
class _ReturnConventionBase { class _ReturnConventionBase {
...@@ -99,6 +100,8 @@ public: ...@@ -99,6 +100,8 @@ public:
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
} else if (r == ReturnConvention::CAPI_RETURN) { } else if (r == ReturnConvention::CAPI_RETURN) {
assert((bool)b ^ (bool)PyErr_Occurred()); assert((bool)b ^ (bool)PyErr_Occurred());
} else if (r == ReturnConvention::MAYBE_EXC) {
assert(b);
} else { } else {
assert(r == ReturnConvention::NOEXC_POSSIBLE); assert(r == ReturnConvention::NOEXC_POSSIBLE);
} }
......
g = 0
class C(object):
@property
def f(self):
print "f"
if g:
raise AttributeError()
c = C()
for i in xrange(100):
print i, getattr(c, 'f', 0)
if i == 50:
g = 1
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