Commit 36894806 authored by Marius Wachtler's avatar Marius Wachtler

set: fix a few reference leaks when an exception gets throwen

this get all triggered by cpythons test_set.py
the problem is mostly that BoxAndHash(Box*) can throw
parent 7c7bcdd3
...@@ -24,7 +24,7 @@ extern "C" Box* createSet() { ...@@ -24,7 +24,7 @@ extern "C" Box* createSet() {
return new BoxedSet(); return new BoxedSet();
} }
void _setAddStolen(BoxedSet* self, STOLEN(BoxAndHash) val) { static void _setAddStolen(BoxedSet* self, STOLEN(BoxAndHash) val) {
auto&& p = self->s.insert(val); auto&& p = self->s.insert(val);
if (!p.second /* already exists */) { if (!p.second /* already exists */) {
// keep the original key // keep the original key
...@@ -32,6 +32,13 @@ void _setAddStolen(BoxedSet* self, STOLEN(BoxAndHash) val) { ...@@ -32,6 +32,13 @@ void _setAddStolen(BoxedSet* self, STOLEN(BoxAndHash) val) {
} }
} }
void _setAddStolen(BoxedSet* self, STOLEN(Box*) val) {
AUTO_DECREF(val);
BoxAndHash val_hashed(val); // this can throw!
incref(val_hashed);
_setAddStolen(self, val_hashed);
}
namespace set { namespace set {
class BoxedSetIterator : public Box { class BoxedSetIterator : public Box {
...@@ -118,8 +125,8 @@ BoxedSet* makeNewSet(BoxedClass* cls, Box* container) { ...@@ -118,8 +125,8 @@ BoxedSet* makeNewSet(BoxedClass* cls, Box* container) {
assert(isSubclass(cls, frozenset_cls) || isSubclass(cls, set_cls)); assert(isSubclass(cls, frozenset_cls) || isSubclass(cls, set_cls));
BoxedSet* rtn = new (cls) BoxedSet(); BoxedSet* rtn = new (cls) BoxedSet();
if (container) { if (container) {
AUTO_DECREF(rtn);
if (PyAnySet_Check(container)) { if (PyAnySet_Check(container)) {
for (auto&& elt : ((BoxedSet*)container)->s) { for (auto&& elt : ((BoxedSet*)container)->s) {
rtn->s.insert(incref(elt)); rtn->s.insert(incref(elt));
...@@ -133,6 +140,7 @@ BoxedSet* makeNewSet(BoxedClass* cls, Box* container) { ...@@ -133,6 +140,7 @@ BoxedSet* makeNewSet(BoxedClass* cls, Box* container) {
_setAddStolen(rtn, elt); _setAddStolen(rtn, elt);
} }
} }
return incref(rtn);
} }
return rtn; return rtn;
} }
...@@ -303,14 +311,14 @@ static BoxedSet* setIntersection2(BoxedSet* self, Box* container) { ...@@ -303,14 +311,14 @@ static BoxedSet* setIntersection2(BoxedSet* self, Box* container) {
RELEASE_ASSERT(PyAnySet_Check(self), ""); RELEASE_ASSERT(PyAnySet_Check(self), "");
BoxedSet* rtn = makeNewSet(self->cls, NULL); BoxedSet* rtn = makeNewSet(self->cls, NULL);
AUTO_DECREF(rtn);
for (auto elt : container->pyElements()) { for (auto elt : container->pyElements()) {
if (self->s.count(elt)) { AUTO_DECREF(elt);
_setAddStolen(rtn, elt); BoxAndHash elt_hashed(elt); // this can throw!
} else { if (self->s.count(elt_hashed))
Py_DECREF(elt); _setAdd(rtn, elt_hashed);
}
} }
return rtn; return incref(rtn);
} }
static Box* setIntersectionUpdate2(BoxedSet* self, Box* other) { static Box* setIntersectionUpdate2(BoxedSet* self, Box* other) {
...@@ -480,6 +488,8 @@ Box* setUnion(BoxedSet* self, BoxedTuple* args) { ...@@ -480,6 +488,8 @@ Box* setUnion(BoxedSet* self, BoxedTuple* args) {
raiseExcHelper(TypeError, "descriptor 'union' requires a 'set' object but received a '%s'", getTypeName(self)); raiseExcHelper(TypeError, "descriptor 'union' requires a 'set' object but received a '%s'", getTypeName(self));
BoxedSet* rtn = makeNewSet(self->cls, self); BoxedSet* rtn = makeNewSet(self->cls, self);
AUTO_DECREF(rtn);
for (auto&& p : self->s) for (auto&& p : self->s)
_setAdd(rtn, p); _setAdd(rtn, p);
...@@ -489,8 +499,7 @@ Box* setUnion(BoxedSet* self, BoxedTuple* args) { ...@@ -489,8 +499,7 @@ Box* setUnion(BoxedSet* self, BoxedTuple* args) {
_setAddStolen(rtn, elt); _setAddStolen(rtn, elt);
} }
} }
return incref(rtn);
return rtn;
} }
static void _setDifferenceUpdate(BoxedSet* self, BoxedTuple* args) { static void _setDifferenceUpdate(BoxedSet* self, BoxedTuple* args) {
...@@ -528,8 +537,9 @@ Box* setDifference(BoxedSet* self, BoxedTuple* args) { ...@@ -528,8 +537,9 @@ Box* setDifference(BoxedSet* self, BoxedTuple* args) {
getTypeName(self)); getTypeName(self));
BoxedSet* rtn = makeNewSet(self->cls, self); BoxedSet* rtn = makeNewSet(self->cls, self);
AUTO_DECREF(rtn);
_setDifferenceUpdate(rtn, args); _setDifferenceUpdate(rtn, args);
return rtn; return incref(rtn);
} }
Box* setSymmetricDifferenceUpdate(BoxedSet* self, Box* other) { Box* setSymmetricDifferenceUpdate(BoxedSet* self, Box* other) {
...@@ -548,8 +558,9 @@ Box* setSymmetricDifference(BoxedSet* self, Box* other) { ...@@ -548,8 +558,9 @@ Box* setSymmetricDifference(BoxedSet* self, Box* other) {
getTypeName(self)); getTypeName(self));
BoxedSet* rtn = makeNewSet(self->cls, self); BoxedSet* rtn = makeNewSet(self->cls, self);
AUTO_DECREF(rtn);
_setSymmetricDifferenceUpdate(rtn, other); _setSymmetricDifferenceUpdate(rtn, other);
return rtn; return incref(rtn);
} }
static Box* setIssubset(BoxedSet* self, Box* container) { static Box* setIssubset(BoxedSet* self, Box* container) {
......
...@@ -42,7 +42,7 @@ public: ...@@ -42,7 +42,7 @@ public:
static int clear(Box* self) noexcept; static int clear(Box* self) noexcept;
}; };
void _setAddStolen(BoxedSet* self, STOLEN(BoxAndHash) val); void _setAddStolen(BoxedSet* self, STOLEN(Box*) val);
} }
#endif #endif
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