# HG changeset patch # Parent aba5f771f5ec9e4004c0375ab4302f246a04bae7 diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9727,33 +9727,46 @@ posix_confstr(PyObject *self, PyObject * PyObject *result = NULL; int name; char buffer[255]; + char *recvbuf = buffer; + char *allocated = NULL; + size_t buflen = sizeof(buffer); size_t len; + const int max_attempts = 20; + int attempts_remaining = max_attempts; if (!PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name)) return NULL; - errno = 0; - len = confstr(name, buffer, sizeof(buffer)); + /* Reset errno before each call as we may need to check it afterwards */ + while (errno = 0, (len = confstr(name, recvbuf, buflen)) > buflen) { + if (--attempts_remaining <= 0) { + PyErr_Format(PyExc_RuntimeError, + "confstr() made %d consecutive requests for a larger " + "buffer; giving up", max_attempts); + goto finally; + } + recvbuf = PyMem_Realloc(allocated, len); + if (recvbuf == NULL) { + PyErr_NoMemory(); + goto finally; + } + allocated = recvbuf; + buflen = len; + } + if (len == 0) { if (errno) { posix_error(); - return NULL; } else { - Py_RETURN_NONE; - } - } - - if (len >= sizeof(buffer)) { - char *buf = PyMem_Malloc(len); - if (buf == NULL) - return PyErr_NoMemory(); - confstr(name, buf, len); - result = PyUnicode_DecodeFSDefaultAndSize(buf, len-1); - PyMem_Free(buf); + result = Py_None; + Py_INCREF(Py_None); + } } else - result = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); + result = PyUnicode_DecodeFSDefaultAndSize(recvbuf, len-1); +finally: + PyMem_Free(allocated); return result; } #endif