Commit ab4fb5dd authored by Jason Madden's avatar Jason Madden

When temporarily decoding an incoming attribute name from a unicode string, be...

When temporarily decoding an incoming attribute name from a unicode string, be careful not to destroy the temoporary PyObject until we're done using its char* buffer. Fixes zopefoundation/Acquisition#5.
parent 52043b7d
......@@ -4,7 +4,9 @@ Changelog
4.2.1 (unreleased)
------------------
- TBD
- Correct several dangling pointer uses in the C extension,
potentially fixing a few interpreter crashes. See
https://github.com/zopefoundation/Acquisition/issues/5.
4.2 (2015-04-04)
----------------
......
......@@ -204,18 +204,18 @@ __of__(PyObject *inst, PyObject *parent)
Py_DECREF(t);
if (r != NULL
&& isWrapper(r)
&& isWrapper(r)
&& WRAPPER(r)->container && isWrapper(WRAPPER(r)->container)
)
while (WRAPPER(r)->obj && isWrapper(WRAPPER(r)->obj)
&& (WRAPPER(WRAPPER(r)->obj)->container ==
&& (WRAPPER(WRAPPER(r)->obj)->container ==
WRAPPER(WRAPPER(r)->container)->obj)
)
{
if (r->ob_refcnt !=1 )
{
t = PyObject_CallFunctionObjArgs((PyObject *)(r->ob_type),
WRAPPER(r)->obj,
t = PyObject_CallFunctionObjArgs((PyObject *)(r->ob_type),
WRAPPER(r)->obj,
WRAPPER(r)->container,
NULL);
Py_DECREF(r);
......@@ -244,7 +244,7 @@ Wrapper_descrget(Wrapper *self, PyObject *inst, PyObject *cls)
Py_INCREF(self);
return (PyObject *)self;
}
return __of__((PyObject *)self, inst);
}
......@@ -272,7 +272,7 @@ Wrapper_traverse(Wrapper *self, visitproc visit, void *arg)
return 0;
}
static int
static int
Wrapper_clear(Wrapper *self)
{
PyObject *tmp;
......@@ -289,7 +289,7 @@ Wrapper_clear(Wrapper *self)
}
static void
Wrapper_dealloc(Wrapper *self)
Wrapper_dealloc(Wrapper *self)
{
Wrapper_clear(self);
self->ob_type->tp_free((PyObject*)self);
......@@ -337,7 +337,7 @@ Wrapper_special(Wrapper *self, char *name, PyObject *oname)
if (strcmp(name,"explicit")==0)
{
if (self->ob_type != (PyTypeObject *)&XaqWrappertype)
return newWrapper(self->obj, self->container,
return newWrapper(self->obj, self->container,
(PyTypeObject *)&XaqWrappertype);
Py_INCREF(self);
return OBJECT(self);
......@@ -357,7 +357,7 @@ Wrapper_special(Wrapper *self, char *name, PyObject *oname)
{
if (PyList_Append(r,OBJECT(self)) >= 0)
{
if (isWrapper(self) && self->container)
if (isWrapper(self) && self->container)
{
self=WRAPPER(self->container);
continue;
......@@ -382,7 +382,7 @@ Wrapper_special(Wrapper *self, char *name, PyObject *oname)
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj)
while (isWrapper(r) && WRAPPER(r)->obj)
{
self=WRAPPER(r);
r=WRAPPER(r)->obj;
......@@ -402,7 +402,7 @@ Wrapper_special(Wrapper *self, char *name, PyObject *oname)
return PyString_FromString("Bob");
}
break;
}
return NULL;
......@@ -448,10 +448,15 @@ err:
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment);
static PyObject *
Wrapper_findattr_name(Wrapper *self, char* name, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int sob, int sco, int explicit, int containment);
static PyObject *
Wrapper_findattr(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
......@@ -474,16 +479,48 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
attribute.
*/
{
PyObject *r, *v, *tb, *tmp;
PyObject *tmp=NULL;
PyObject *result;
char *name="";
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (PyUnicode_Check(oname)) {
else if (PyUnicode_Check(oname)) {
tmp=PyUnicode_AsASCIIString(oname);
if (tmp==NULL) return NULL;
name=PyString_AS_STRING(tmp);
Py_DECREF(tmp);
}
result = Wrapper_findattr_name(self, name, oname, filter, extra, orig,
sob, sco, explicit, containment);
Py_XDECREF(tmp);
return result;
}
static PyObject *
Wrapper_findattr_name(Wrapper *self, char* name, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int sob, int sco, int explicit, int containment)
/*
Exactly the same as Wrapper_findattr, except that the incoming
Python name string/unicode object has already been decoded
into a C string. This helper function lets us more easily manage
the lifetime of any temporary allocations.
This function uses Wrapper_acquire, which only takes the original
oname value, not the decoded value. That function can call back into
this one (via Wrapper_findattr). Although that may lead to a few
temporary allocations as we walk through the containment hierarchy,
it is correct: This function may modify its internal view of the
`name` value, and if that were propagated up the hierarchy
the incorrect name may be looked up.
*/
{
PyObject *r, *v, *tb;
if ((*name=='a' && name[1]=='q' && name[2]=='_') ||
(strcmp(name, "__parent__")==0))
{
......@@ -505,7 +542,7 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
}
else PyErr_Clear();
}
else if (*name=='_' && name[1]=='_' &&
else if (*name=='_' && name[1]=='_' &&
(strcmp(name+2,"reduce__")==0 ||
strcmp(name+2,"reduce_ex__")==0 ||
strcmp(name+2,"getstate__")==0
......@@ -527,12 +564,12 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
return NULL;
}
if ((r=Wrapper_findattr(WRAPPER(self->obj),
oname, filter, extra, orig, 1,
oname, filter, extra, orig, 1,
/* Search object container if explicit,
or object is implicit acquirer */
explicit ||
self->obj->ob_type ==
self->obj->ob_type ==
(PyTypeObject*)&Wrappertype,
explicit, containment)))
{
......@@ -565,7 +602,7 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
if (r==Acquired)
{
Py_DECREF(r);
return Wrapper_acquire(self, oname, filter, extra, orig, 1,
return Wrapper_acquire(self, oname, filter, extra, orig, 1,
containment);
}
......@@ -595,8 +632,8 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
}
/* Lookup has failed, acquire it from parent. */
if (sco && (*name != '_' || explicit))
return Wrapper_acquire(self, oname, filter, extra, orig, explicit,
if (sco && (*name != '_' || explicit))
return Wrapper_acquire(self, oname, filter, extra, orig, explicit,
containment);
PyErr_SetObject(PyExc_AttributeError,oname);
......@@ -604,7 +641,7 @@ Wrapper_findattr(Wrapper *self, PyObject *oname,
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment)
{
......@@ -622,10 +659,10 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
/* Try to optimize search by recognizing repeated
objects in path. */
if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->container)
WRAPPER(self->container)->container)
sco=0;
else if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->obj)
WRAPPER(self->container)->obj)
sob=0;
}
......@@ -638,9 +675,9 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
}
r=Wrapper_findattr((Wrapper*)self->container,
oname, filter, extra, orig, sob, sco, explicit,
oname, filter, extra, orig, sob, sco, explicit,
containment);
if (r && has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
......@@ -663,7 +700,7 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
Py_DECREF(r); /* don't need __parent__ anymore */
r=Wrapper_findattr((Wrapper*)self->container,
oname, filter, extra, orig, sob, sco, explicit,
oname, filter, extra, orig, sob, sco, explicit,
containment);
/* There's no need to DECREF the wrapper here because it's
not stored in self->container, thus 'self' owns its
......@@ -695,9 +732,9 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
switch(apply_filter(filter,self->container,oname,r,
extra,orig))
{
case -1:
case -1:
return NULL;
case 1:
case 1:
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
......@@ -714,7 +751,7 @@ Wrapper_acquire(Wrapper *self, PyObject *oname,
}
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
......@@ -732,62 +769,73 @@ Wrapper_getattro(Wrapper *self, PyObject *oname)
static PyObject *
Xaq_getattro(Wrapper *self, PyObject *oname)
{
PyObject *tmp;
PyObject *tmp=NULL;
PyObject *result;
char *name="";
/* Special case backward-compatible acquire method. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (PyUnicode_Check(oname)) {
else if (PyUnicode_Check(oname)) {
tmp=PyUnicode_AsASCIIString(oname);
if (tmp==NULL) return NULL;
name=PyString_AS_STRING(tmp);
Py_DECREF(tmp);
}
if (*name=='a' && name[1]=='c' && strcmp(name+2,"quire")==0)
return Py_FindAttr(OBJECT(self),oname);
result = Py_FindAttr(OBJECT(self),oname);
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 0, 0, 0);
else if (self->obj || self->container)
result = Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 0, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
else result = Py_FindAttr(OBJECT(self),oname);
Py_XDECREF(tmp);
return result;
}
static int
Wrapper_setattro(Wrapper *self, PyObject *oname, PyObject *v)
{
PyObject *tmp;
PyObject *tmp=NULL;
char *name="";
int result;
/* Allow assignment to parent, to change context. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (PyUnicode_Check(oname)) {
else if (PyUnicode_Check(oname)) {
tmp=PyUnicode_AsASCIIString(oname);
if (tmp==NULL) return -1;
name=PyString_AS_STRING(tmp);
Py_DECREF(tmp);
}
if ((*name=='a' && name[1]=='q' && name[2]=='_'
if ((*name=='a' && name[1]=='q' && name[2]=='_'
&& strcmp(name+3,"parent")==0) || (strcmp(name, "__parent__")==0))
{
Py_XINCREF(v);
ASSIGN(self->container, v);
return 0;
result = 0;
}
if (self->obj)
else if (self->obj)
{
/* Unwrap passed in wrappers! */
while (v && isWrapper(v))
v=WRAPPER(v)->obj;
v=WRAPPER(v)->obj;
if (v) return PyObject_SetAttr(self->obj, oname, v);
else return PyObject_DelAttr(self->obj, oname);
if (v) result = PyObject_SetAttr(self->obj, oname, v);
else result = PyObject_DelAttr(self->obj, oname);
}
PyErr_SetString(PyExc_AttributeError,
else
{
PyErr_SetString(PyExc_AttributeError,
"Attempt to set attribute on empty acquisition wrapper");
return -1;
result = -1;
}
Py_XDECREF(tmp);
return result;
}
static int
......@@ -821,12 +869,12 @@ Wrapper_compare(Wrapper *self, PyObject *w)
ASSIGN(m, PyObject_CallFunction(m, "O", w));
UNLESS (m) return -1;
r=PyInt_AsLong(m);
Py_DECREF(m);
return r;
return r;
}
static PyObject *
......@@ -998,7 +1046,7 @@ Wrapper_contains(Wrapper *self, PyObject *v)
Instead the base object needs to be checked and the wrapper must only
be used when actually calling `__getitem__` or setting up a sequence
iterator. */
static PyObject *
static PyObject *
Wrapper_iter(Wrapper *self)
{
PyObject *obj = self->obj;
......@@ -1156,7 +1204,7 @@ Wrapper_or(Wrapper *self, PyObject *o)
return CallMethodO(OBJECT(self),py__or__,Build("(O)", o),NULL);
}
static int
static int
Wrapper_coerce(Wrapper **self, PyObject **o)
{
PyObject *m;
......@@ -1180,7 +1228,7 @@ Wrapper_coerce(Wrapper **self, PyObject **o)
err:
Py_DECREF(m);
return -1;
return -1;
}
static PyObject *
......@@ -1291,7 +1339,7 @@ Wrapper_acquire_method(Wrapper *self, PyObject *args, PyObject *kw)
if (filter==Py_None) filter=0;
result = Wrapper_findattr(self,name,filter,extra,OBJECT(self),1,
explicit ||
explicit ||
self->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
if (result == NULL && defalt != NULL) {
......@@ -1326,7 +1374,7 @@ Wrapper_inContextOf(Wrapper *self, PyObject *args)
PyObject *
Wrappers_are_not_picklable(PyObject *wrapper, PyObject *args)
{
PyErr_SetString(PyExc_TypeError,
PyErr_SetString(PyExc_TypeError,
"Can't pickle objects in acquisition wrappers.");
return NULL;
}
......@@ -1338,10 +1386,10 @@ Wrapper___getnewargs__(PyObject *self)
}
static struct PyMethodDef Wrapper_methods[] = {
{"acquire", (PyCFunction)Wrapper_acquire_method,
{"acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_acquire", (PyCFunction)Wrapper_acquire_method,
{"aq_acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_inContextOf", (PyCFunction)Wrapper_inContextOf, METH_VARARGS,
......@@ -1355,7 +1403,7 @@ static struct PyMethodDef Wrapper_methods[] = {
{"__reduce_ex__", (PyCFunction)Wrappers_are_not_picklable, METH_VARARGS,
"Wrappers are not picklable"},
{"__unicode__", (PyCFunction)Wrapper_unicode, METH_NOARGS,
"Unicode"},
"Unicode"},
{NULL, NULL} /* sentinel */
};
......@@ -1381,7 +1429,7 @@ static PyExtensionClass Wrappertype = {
(getattrofunc)Wrapper_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* tp_as_buffer */ 0,
/* tp_flags */ Py_TPFLAGS_DEFAULT
/* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC
#ifdef Py_TPFLAGS_HAVE_VERSION_TAG
......@@ -1428,7 +1476,7 @@ static PyExtensionClass XaqWrappertype = {
(getattrofunc)Xaq_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* tp_as_buffer */ 0,
/* tp_flags */ Py_TPFLAGS_DEFAULT
/* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC
#ifdef Py_TPFLAGS_HAVE_VERSION_TAG
......@@ -1490,15 +1538,15 @@ xaq_of(PyObject *self, PyObject *args)
}
static struct PyMethodDef Acquirer_methods[] = {
{"__of__",(PyCFunction)acquire_of, METH_VARARGS,
{"__of__",(PyCFunction)acquire_of, METH_VARARGS,
"__of__(context) -- return the object in a context"},
{NULL, NULL} /* sentinel */
};
static struct PyMethodDef Xaq_methods[] = {
{"__of__",(PyCFunction)xaq_of, METH_VARARGS,""},
{NULL, NULL} /* sentinel */
};
......@@ -1514,9 +1562,9 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
if (isWrapper(self)) {
result = Wrapper_findattr(
WRAPPER(self), name, filter, extra, OBJECT(self),1,
explicit ||
explicit ||
WRAPPER(self)->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
explicit, containment);
goto check_default;
}
/* Not wrapped; check if we have a __parent__ pointer. If that's
......@@ -1551,9 +1599,9 @@ capi_aq_acquire(PyObject *self, PyObject *name, PyObject *filter,
/* Crap, we've got to construct a wrapper so we can use
Wrapper_findattr */
UNLESS (self=newWrapper(self, Py_None, (PyTypeObject*)&Wrappertype))
UNLESS (self=newWrapper(self, Py_None, (PyTypeObject*)&Wrappertype))
return NULL;
result=Wrapper_findattr(WRAPPER(self), name, filter, extra, OBJECT(self),
1, 1, explicit, containment);
......@@ -1602,8 +1650,8 @@ capi_aq_get(PyObject *self, PyObject *name, PyObject *defalt, int containment)
{
PyObject *result = NULL, *v, *tb;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
result=Wrapper_findattr(WRAPPER(self), name, 0, 0, OBJECT(self), 1, 1, 1,
if (isWrapper(self))
result=Wrapper_findattr(WRAPPER(self), name, 0, 0, OBJECT(self), 1, 1, 1,
containment);
/* Not wrapped; check if we have a __parent__ pointer. If that's
the case, create a wrapper and pretend it's business as usual. */
......@@ -1626,7 +1674,7 @@ capi_aq_get(PyObject *self, PyObject *name, PyObject *defalt, int containment)
return NULL;
}
Py_XDECREF(result); Py_XDECREF(v); Py_XDECREF(tb);
result=PyObject_GetAttr(self, name);
}
......@@ -1636,7 +1684,7 @@ capi_aq_get(PyObject *self, PyObject *name, PyObject *defalt, int containment)
result=defalt;
Py_INCREF(result);
}
return result;
}
......@@ -1646,14 +1694,14 @@ module_aq_get(PyObject *r, PyObject *args)
{
PyObject *self, *name, *defalt=0;
int containment=0;
UNLESS (PyArg_ParseTuple(args, "OO|Oi",
UNLESS (PyArg_ParseTuple(args, "OO|Oi",
&self, &name, &defalt, &containment
)) return NULL;
return capi_aq_get(self, name, defalt, containment);
}
static int
static int
capi_aq_iswrapper(PyObject *self) {
return isWrapper(self);
}
......@@ -1662,12 +1710,12 @@ static PyObject *
capi_aq_base(PyObject *self)
{
PyObject *result;
if (! isWrapper(self))
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj)
{
result=WRAPPER(self)->obj;
......@@ -1735,12 +1783,12 @@ static PyObject *
capi_aq_self(PyObject *self)
{
PyObject *result;
if (! isWrapper(self))
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj) result=WRAPPER(self)->obj;
else result=Py_None;
......@@ -1760,7 +1808,7 @@ static PyObject *
capi_aq_inner(PyObject *self)
{
PyObject *result;
if (! isWrapper(self))
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
......@@ -1769,7 +1817,7 @@ capi_aq_inner(PyObject *self)
if (WRAPPER(self)->obj)
{
result=WRAPPER(self)->obj;
while (isWrapper(result) && WRAPPER(result)->obj)
while (isWrapper(result) && WRAPPER(result)->obj)
{
self=result;
result=WRAPPER(result)->obj;
......@@ -1810,7 +1858,7 @@ capi_aq_chain(PyObject *self, int containment)
if (PyList_Append(result,OBJECT(self)) < 0)
goto err;
}
if (WRAPPER(self)->container)
if (WRAPPER(self)->container)
{
self=WRAPPER(self)->container;
continue;
......@@ -1841,7 +1889,7 @@ capi_aq_chain(PyObject *self, int containment)
break;
}
return result;
err:
Py_DECREF(result);
......@@ -1908,7 +1956,7 @@ module_aq_inContextOf(PyObject *ignored, PyObject *args)
}
static struct PyMethodDef methods[] = {
{"aq_acquire", (PyCFunction)module_aq_acquire, METH_VARARGS|METH_KEYWORDS,
{"aq_acquire", (PyCFunction)module_aq_acquire, METH_VARARGS|METH_KEYWORDS,
"aq_acquire(ob, name [, filter, extra, explicit]) -- "
"Get an attribute, acquiring it if necessary"
},
......@@ -1916,16 +1964,16 @@ static struct PyMethodDef methods[] = {
"aq_get(ob, name [, default]) -- "
"Get an attribute, acquiring it if necessary."
},
{"aq_base", (PyCFunction)module_aq_base, METH_VARARGS,
{"aq_base", (PyCFunction)module_aq_base, METH_VARARGS,
"aq_base(ob) -- Get the object unwrapped"},
{"aq_parent", (PyCFunction)module_aq_parent, METH_VARARGS,
{"aq_parent", (PyCFunction)module_aq_parent, METH_VARARGS,
"aq_parent(ob) -- Get the parent of an object"},
{"aq_self", (PyCFunction)module_aq_self, METH_VARARGS,
{"aq_self", (PyCFunction)module_aq_self, METH_VARARGS,
"aq_self(ob) -- Get the object with the outermost wrapper removed"},
{"aq_inner", (PyCFunction)module_aq_inner, METH_VARARGS,
{"aq_inner", (PyCFunction)module_aq_inner, METH_VARARGS,
"aq_inner(ob) -- "
"Get the object with all but the innermost wrapper removed"},
{"aq_chain", (PyCFunction)module_aq_chain, METH_VARARGS,
{"aq_chain", (PyCFunction)module_aq_chain, METH_VARARGS,
"aq_chain(ob [, containment]) -- "
"Get a list of objects in the acquisition environment"},
{"aq_inContextOf", (PyCFunction)module_aq_inContextOf, METH_VARARGS,
......
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