diff options
author | Martin v. Löwis <martin@v.loewis.de> | 2008-08-12 14:49:50 (GMT) |
---|---|---|
committer | Martin v. Löwis <martin@v.loewis.de> | 2008-08-12 14:49:50 (GMT) |
commit | f91d46a17d85da323895950852093117bc21f860 (patch) | |
tree | c6a3e68cf22a6a102f9c1dc780438f0307b6588f /Python | |
parent | aa8efbf08469c3667ed22362c0e10b83ae124c0b (diff) | |
download | cpython-f91d46a17d85da323895950852093117bc21f860.zip cpython-f91d46a17d85da323895950852093117bc21f860.tar.gz cpython-f91d46a17d85da323895950852093117bc21f860.tar.bz2 |
Issue #3139: Make buffer-interface thread-safe wrt. PyArg_ParseTuple,
by denying s# to parse objects that have a releasebuffer procedure,
and introducing s*.
More module might need to get converted to use s*.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/getargs.c | 132 |
1 files changed, 123 insertions, 9 deletions
diff --git a/Python/getargs.c b/Python/getargs.c index 162cf6f..7c9774f 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -44,6 +44,7 @@ static char *converttuple(PyObject *, const char **, va_list *, int, static char *convertsimple(PyObject *, const char **, va_list *, int, char *, size_t, PyObject **); static Py_ssize_t convertbuffer(PyObject *, void **p, char **); +static int getbuffer(PyObject *, Py_buffer *, char**); static int vgetargskeywords(PyObject *, PyObject *, const char *, char **, va_list *, int); @@ -773,7 +774,32 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } case 's': {/* string */ - if (*format == '#') { + if (*format == '*') { + Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); + + if (PyString_Check(arg)) { + PyBuffer_FillInfo(p, arg, + PyString_AS_STRING(arg), PyString_GET_SIZE(arg), + 1, 0); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(arg)) { + uarg = UNICODE_DEFAULT_ENCODING(arg); + if (uarg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf, bufsize); + PyBuffer_FillInfo(p, arg, + PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg), + 1, 0); + } +#endif + else { /* any buffer-like object */ + char *buf; + if (getbuffer(arg, p, &buf) < 0) + return converterr(buf, arg, msgbuf, bufsize); + } + format++; + } else if (*format == '#') { void **p = (void **)va_arg(*p_va, char **); FETCH_SIZE; @@ -823,7 +849,34 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } case 'z': {/* string, may be NULL (None) */ - if (*format == '#') { /* any buffer-like object */ + if (*format == '*') { + Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *); + + if (arg == Py_None) + PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0); + else if (PyString_Check(arg)) { + PyBuffer_FillInfo(p, arg, + PyString_AS_STRING(arg), PyString_GET_SIZE(arg), + 1, 0); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(arg)) { + uarg = UNICODE_DEFAULT_ENCODING(arg); + if (uarg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf, bufsize); + PyBuffer_FillInfo(p, arg, + PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg), + 1, 0); + } +#endif + else { /* any buffer-like object */ + char *buf; + if (getbuffer(arg, p, &buf) < 0) + return converterr(buf, arg, msgbuf, bufsize); + } + format++; + } else if (*format == '#') { /* any buffer-like object */ void **p = (void **)va_arg(*p_va, char **); FETCH_SIZE; @@ -1144,23 +1197,49 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'w': { /* memory buffer, read-write access */ void **p = va_arg(*p_va, void **); + void *res; PyBufferProcs *pb = arg->ob_type->tp_as_buffer; Py_ssize_t count; - - if (pb == NULL || + + if (pb && pb->bf_releasebuffer && *format != '*') + /* Buffer must be released, yet caller does not use + the Py_buffer protocol. */ + return converterr("pinned buffer", arg, msgbuf, bufsize); + + if (pb && pb->bf_getbuffer && *format == '*') { + /* Caller is interested in Py_buffer, and the object + supports it directly. */ + format++; + if (pb->bf_getbuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { + PyErr_Clear(); + return converterr("read-write buffer", arg, msgbuf, bufsize); + } + if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) + return converterr("contiguous buffer", arg, msgbuf, bufsize); + break; + } + + if (pb == NULL || pb->bf_getwritebuffer == NULL || pb->bf_getsegcount == NULL) return converterr("read-write buffer", arg, msgbuf, bufsize); if ((*pb->bf_getsegcount)(arg, NULL) != 1) return converterr("single-segment read-write buffer", arg, msgbuf, bufsize); - if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0) + if ((count = pb->bf_getwritebuffer(arg, 0, &res)) < 0) return converterr("(unspecified)", arg, msgbuf, bufsize); - if (*format == '#') { - FETCH_SIZE; - STORE_SIZE(count); + if (*format == '*') { + PyBuffer_FillInfo((Py_buffer*)p, arg, res, count, 1, 0); format++; } + else { + *p = res; + if (*format == '#') { + FETCH_SIZE; + STORE_SIZE(count); + format++; + } + } break; } @@ -1186,6 +1265,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, "string or single-segment read-only buffer", arg, msgbuf, bufsize); + if (pb->bf_releasebuffer) + return converterr( + "string or pinned buffer", + arg, msgbuf, bufsize); + count = pb->bf_getcharbuffer(arg, 0, p); if (count < 0) return converterr("(unspecified)", arg, msgbuf, bufsize); @@ -1212,7 +1296,8 @@ convertbuffer(PyObject *arg, void **p, char **errmsg) Py_ssize_t count; if (pb == NULL || pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL) { + pb->bf_getsegcount == NULL || + pb->bf_releasebuffer != NULL) { *errmsg = "string or read-only buffer"; return -1; } @@ -1226,6 +1311,33 @@ convertbuffer(PyObject *arg, void **p, char **errmsg) return count; } +static int +getbuffer(PyObject *arg, Py_buffer *view, char**errmsg) +{ + void *buf; + Py_ssize_t count; + PyBufferProcs *pb = arg->ob_type->tp_as_buffer; + if (pb == NULL) { + *errmsg = "string or buffer"; + return -1; + } + if (pb->bf_getbuffer) { + if (pb->bf_getbuffer(arg, view, 0) < 0) + return -1; + if (!PyBuffer_IsContiguous(view, 'C')) { + *errmsg = "contiguous buffer"; + return -1; + } + return 0; + } + + count = convertbuffer(arg, &buf, errmsg); + if (count < 0) + return count; + PyBuffer_FillInfo(view, NULL, buf, count, 1, 0); + return 0; +} + /* Support for keyword arguments donated by Geoff Philbrick <philbric@delphi.hks.com> */ @@ -1566,6 +1678,8 @@ skipitem(const char **p_format, va_list *p_va, int flags) else (void) va_arg(*p_va, int *); format++; + } else if ((c == 's' || c == 'z') && *format == '*') { + format++; } break; } |