diff options
Diffstat (limited to 'Python/getargs.c')
| -rw-r--r-- | Python/getargs.c | 243 | 
1 files changed, 137 insertions, 106 deletions
| diff --git a/Python/getargs.c b/Python/getargs.c index 8aab067..4418ebb 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -20,12 +20,12 @@ int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,  #ifdef HAVE_DECLSPEC_DLL  /* Export functions */ -PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, char *, ...); -PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, char *, ...); +PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); +PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...);  PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *,                                                    const char *, char **, ...);  PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); -PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, char *, va_list); +PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list);  PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *,                                                const char *, char **, va_list);  #endif @@ -56,18 +56,18 @@ typedef struct {  /* Forward */  static int vgetargs1(PyObject *, const char *, va_list *, int);  static void seterror(Py_ssize_t, const char *, int *, const char *, const char *); -static char *convertitem(PyObject *, const char **, va_list *, int, int *, -                         char *, size_t, freelist_t *); -static char *converttuple(PyObject *, const char **, va_list *, int, -                          int *, char *, size_t, int, freelist_t *); -static char *convertsimple(PyObject *, const char **, va_list *, int, char *, -                           size_t, freelist_t *); -static Py_ssize_t convertbuffer(PyObject *, void **p, char **); -static int getbuffer(PyObject *, Py_buffer *, char**); +static const char *convertitem(PyObject *, const char **, va_list *, int, int *, +                               char *, size_t, freelist_t *); +static const char *converttuple(PyObject *, const char **, va_list *, int, +                                int *, char *, size_t, int, freelist_t *); +static const char *convertsimple(PyObject *, const char **, va_list *, int, +                                 char *, size_t, freelist_t *); +static Py_ssize_t convertbuffer(PyObject *, void **p, const char **); +static int getbuffer(PyObject *, Py_buffer *, const char**);  static int vgetargskeywords(PyObject *, PyObject *,                              const char *, char **, va_list *, int); -static char *skipitem(const char **, va_list *, int); +static const char *skipitem(const char **, va_list *, int);  int  PyArg_Parse(PyObject *args, const char *format, ...) @@ -82,7 +82,7 @@ PyArg_Parse(PyObject *args, const char *format, ...)  }  int -_PyArg_Parse_SizeT(PyObject *args, char *format, ...) +_PyArg_Parse_SizeT(PyObject *args, const char *format, ...)  {      int retval;      va_list va; @@ -107,7 +107,7 @@ PyArg_ParseTuple(PyObject *args, const char *format, ...)  }  int -_PyArg_ParseTuple_SizeT(PyObject *args, char *format, ...) +_PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...)  {      int retval;      va_list va; @@ -130,7 +130,7 @@ PyArg_VaParse(PyObject *args, const char *format, va_list va)  }  int -_PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va) +_PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va)  {      va_list lva; @@ -208,7 +208,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)      int endfmt = 0;      const char *formatsave = format;      Py_ssize_t i, len; -    char *msg; +    const char *msg;      int compat = flags & FLAG_COMPAT;      freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];      freelist_t freelist; @@ -394,7 +394,12 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,          PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg);          message = buf;      } -    PyErr_SetString(PyExc_TypeError, message); +    if (msg[0] == '(') { +        PyErr_SetString(PyExc_SystemError, message); +    } +    else { +        PyErr_SetString(PyExc_TypeError, message); +    }  } @@ -416,7 +421,7 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,        and msgbuf is returned.  */ -static char * +static const char *  converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,               int *levels, char *msgbuf, size_t bufsize, int toplevel,               freelist_t *freelist) @@ -474,7 +479,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,      format = *p_format;      for (i = 0; i < n; i++) { -        char *msg; +        const char *msg;          PyObject *item;          item = PySequence_GetItem(arg, i);          if (item == NULL) { @@ -501,11 +506,11 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,  /* Convert a single item. */ -static char * +static const char *  convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,              int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist)  { -    char *msg; +    const char *msg;      const char *format = *p_format;      if (*format == '(' /* ')' */) { @@ -530,7 +535,7 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,  /* Format an error message generated by convertsimple(). */ -static char * +static const char *  converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)  {      assert(expected != NULL); @@ -572,7 +577,7 @@ float_argument_error(PyObject *arg)     When you add new format codes, please don't forget poor skipitem() below.  */ -static char * +static const char *  convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,                char *msgbuf, size_t bufsize, freelist_t *freelist)  { @@ -857,7 +862,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,      case 'y': {/* any bytes-like object */          void **p = (void **)va_arg(*p_va, char **); -        char *buf; +        const char *buf;          Py_ssize_t count;          if (*format == '*') {              if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) @@ -904,7 +909,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,                  PyBuffer_FillInfo(p, arg, sarg, len, 1, 0);              }              else { /* any bytes-like object */ -                char *buf; +                const char *buf;                  if (getbuffer(arg, p, &buf) < 0)                      return converterr(buf, arg, msgbuf, bufsize);              } @@ -934,7 +939,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,              }              else { /* read-only bytes-like object */                  /* XXX Really? */ -                char *buf; +                const char *buf;                  Py_ssize_t count = convertbuffer(arg, p, &buf);                  if (count < 0)                      return converterr(buf, arg, msgbuf, bufsize); @@ -1051,35 +1056,25 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,                  return converterr("(AsCharBuffer failed)",                                    arg, msgbuf, bufsize);          } -        else { -            PyObject *u; - -            /* Convert object to Unicode */ -            u = PyUnicode_FromObject(arg); -            if (u == NULL) -                return converterr( -                    "string or unicode or text buffer", -                    arg, msgbuf, bufsize); - +        else if (PyUnicode_Check(arg)) {              /* Encode object; use default error handling */ -            s = PyUnicode_AsEncodedString(u, +            s = PyUnicode_AsEncodedString(arg,                                            encoding,                                            NULL); -            Py_DECREF(u);              if (s == NULL)                  return converterr("(encoding failed)",                                    arg, msgbuf, bufsize); -            if (!PyBytes_Check(s)) { -                Py_DECREF(s); -                return converterr( -                    "(encoder failed to return bytes)", -                    arg, msgbuf, bufsize); -            } +            assert(PyBytes_Check(s));              size = PyBytes_GET_SIZE(s);              ptr = PyBytes_AS_STRING(s);              if (ptr == NULL)                  ptr = "";          } +        else { +            return converterr( +                recode_strings ? "str" : "str, bytes or bytearray", +                arg, msgbuf, bufsize); +        }          /* Write output; output is guaranteed to be 0-terminated */          if (*format == '#') { @@ -1129,7 +1124,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,              } else {                  if (size + 1 > BUFFER_LEN) {                      Py_DECREF(s); -                    PyErr_Format(PyExc_TypeError, +                    PyErr_Format(PyExc_ValueError,                                   "encoded string too long "                                   "(%zd, maximum length %zd)",                                   (Py_ssize_t)size, (Py_ssize_t)(BUFFER_LEN-1)); @@ -1283,7 +1278,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,  }  static Py_ssize_t -convertbuffer(PyObject *arg, void **p, char **errmsg) +convertbuffer(PyObject *arg, void **p, const char **errmsg)  {      PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer;      Py_ssize_t count; @@ -1305,7 +1300,7 @@ convertbuffer(PyObject *arg, void **p, char **errmsg)  }  static int -getbuffer(PyObject *arg, Py_buffer *view, char **errmsg) +getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg)  {      if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) {          *errmsg = "bytes-like object"; @@ -1448,7 +1443,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,      const char *fname, *msg, *custom_msg, *keyword;      int min = INT_MAX;      int max = INT_MAX; -    int i, len; +    int i, pos, len; +    int skip = 0;      Py_ssize_t nargs, nkeywords;      PyObject *current_arg;      freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; @@ -1476,9 +1472,17 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,              custom_msg++;      } +    /* scan kwlist and count the number of positional-only parameters */ +    for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) { +    }      /* scan kwlist and get greatest possible nbr of args */ -    for (len=0; kwlist[len]; len++) -        continue; +    for (len = pos; kwlist[len]; len++) { +        if (!*kwlist[len]) { +            PyErr_SetString(PyExc_SystemError, +                            "Empty keyword parameter name"); +            return cleanreturn(0, &freelist); +        } +    }      if (len > STATIC_FREELIST_ENTRIES) {          freelist.entries = PyMem_NEW(freelistentry_t, len); @@ -1507,7 +1511,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,          keyword = kwlist[i];          if (*format == '|') {              if (min != INT_MAX) { -                PyErr_SetString(PyExc_RuntimeError, +                PyErr_SetString(PyExc_SystemError,                                  "Invalid format string (| specified twice)");                  return cleanreturn(0, &freelist);              } @@ -1516,14 +1520,14 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,              format++;              if (max != INT_MAX) { -                PyErr_SetString(PyExc_RuntimeError, +                PyErr_SetString(PyExc_SystemError,                                  "Invalid format string ($ before |)");                  return cleanreturn(0, &freelist);              }          }          if (*format == '$') {              if (max != INT_MAX) { -                PyErr_SetString(PyExc_RuntimeError, +                PyErr_SetString(PyExc_SystemError,                                  "Invalid format string ($ specified twice)");                  return cleanreturn(0, &freelist);              } @@ -1531,6 +1535,14 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,              max = i;              format++; +            if (max < pos) { +                PyErr_SetString(PyExc_SystemError, +                                "Empty parameter name after $"); +                return cleanreturn(0, &freelist); +            } +            if (skip) { +                break; +            }              if (max < nargs) {                  PyErr_Format(PyExc_TypeError,                               "Function takes %s %d positional arguments" @@ -1541,66 +1553,86 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,              }          }          if (IS_END_OF_FORMAT(*format)) { -            PyErr_Format(PyExc_RuntimeError, +            PyErr_Format(PyExc_SystemError,                           "More keyword list entries (%d) than "                           "format specifiers (%d)", len, i);              return cleanreturn(0, &freelist);          } -        current_arg = NULL; -        if (nkeywords) { -            current_arg = PyDict_GetItemString(keywords, keyword); -        } -        if (current_arg) { -            --nkeywords; -            if (i < nargs) { -                /* arg present in tuple and in dict */ -                PyErr_Format(PyExc_TypeError, -                             "Argument given by name ('%s') " -                             "and position (%d)", -                             keyword, i+1); -                return cleanreturn(0, &freelist); +        if (!skip) { +            current_arg = NULL; +            if (nkeywords && i >= pos) { +                current_arg = PyDict_GetItemString(keywords, keyword); +                if (!current_arg && PyErr_Occurred()) { +                    return cleanreturn(0, &freelist); +                }              } -        } -        else if (nkeywords && PyErr_Occurred()) -            return cleanreturn(0, &freelist); -        else if (i < nargs) -            current_arg = PyTuple_GET_ITEM(args, i); - -        if (current_arg) { -            msg = convertitem(current_arg, &format, p_va, flags, -                levels, msgbuf, sizeof(msgbuf), &freelist); -            if (msg) { -                seterror(i+1, msg, levels, fname, custom_msg); -                return cleanreturn(0, &freelist); +            if (current_arg) { +                --nkeywords; +                if (i < nargs) { +                    /* arg present in tuple and in dict */ +                    PyErr_Format(PyExc_TypeError, +                                 "Argument given by name ('%s') " +                                 "and position (%d)", +                                 keyword, i+1); +                    return cleanreturn(0, &freelist); +                } +            } +            else if (i < nargs) +                current_arg = PyTuple_GET_ITEM(args, i); + +            if (current_arg) { +                msg = convertitem(current_arg, &format, p_va, flags, +                    levels, msgbuf, sizeof(msgbuf), &freelist); +                if (msg) { +                    seterror(i+1, msg, levels, fname, custom_msg); +                    return cleanreturn(0, &freelist); +                } +                continue;              } -            continue; -        } -        if (i < min) { -            PyErr_Format(PyExc_TypeError, "Required argument " -                         "'%s' (pos %d) not found", -                         keyword, i+1); -            return cleanreturn(0, &freelist); +            if (i < min) { +                if (i < pos) { +                    assert (min == INT_MAX); +                    assert (max == INT_MAX); +                    skip = 1; +                } +                else { +                    PyErr_Format(PyExc_TypeError, "Required argument " +                                "'%s' (pos %d) not found", +                                keyword, i+1); +                    return cleanreturn(0, &freelist); +                } +            } +            /* current code reports success when all required args +             * fulfilled and no keyword args left, with no further +             * validation. XXX Maybe skip this in debug build ? +             */ +            if (!nkeywords && !skip) { +                return cleanreturn(1, &freelist); +            }          } -        /* current code reports success when all required args -         * fulfilled and no keyword args left, with no further -         * validation. XXX Maybe skip this in debug build ? -         */ -        if (!nkeywords) -            return cleanreturn(1, &freelist);          /* We are into optional args, skip thru to any remaining           * keyword args */          msg = skipitem(&format, p_va, flags);          if (msg) { -            PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg, +            PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,                           format);              return cleanreturn(0, &freelist);          }      } +    if (skip) { +        PyErr_Format(PyExc_TypeError, +                     "Function takes %s %d positional arguments" +                     " (%d given)", +                     (Py_MIN(pos, min) < i) ? "at least" : "exactly", +                     Py_MIN(pos, min), nargs); +        return cleanreturn(0, &freelist); +    } +      if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { -        PyErr_Format(PyExc_RuntimeError, +        PyErr_Format(PyExc_SystemError,              "more argument specifiers than keyword list entries "              "(remaining format:'%s')", format);          return cleanreturn(0, &freelist); @@ -1618,7 +1650,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,                  return cleanreturn(0, &freelist);              }              for (i = 0; i < len; i++) { -                if (!PyUnicode_CompareWithASCIIString(key, kwlist[i])) { +                if (*kwlist[i] && !PyUnicode_CompareWithASCIIString(key, kwlist[i])) {                      match = 1;                      break;                  } @@ -1637,7 +1669,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,  } -static char * +static const char *  skipitem(const char **p_format, va_list *p_va, int flags)  {      const char *format = *p_format; @@ -1730,7 +1762,7 @@ skipitem(const char **p_format, va_list *p_va, int flags)      case '(':           /* bypass tuple, not handled at all previously */          { -            char *msg; +            const char *msg;              for (;;) {                  if (*format==')')                      break; @@ -1766,16 +1798,9 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m      PyObject **o;      va_list vargs; -#ifdef HAVE_STDARG_PROTOTYPES -    va_start(vargs, max); -#else -    va_start(vargs); -#endif -      assert(min >= 0);      assert(min <= max);      if (!PyTuple_Check(args)) { -        va_end(vargs);          PyErr_SetString(PyExc_SystemError,              "PyArg_UnpackTuple() argument list is not a tuple");          return 0; @@ -1793,9 +1818,10 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m                  "unpacked tuple should have %s%zd elements,"                  " but has %zd",                  (min == max ? "" : "at least "), min, l); -        va_end(vargs);          return 0;      } +    if (l == 0) +        return 1;      if (l > max) {          if (name != NULL)              PyErr_Format( @@ -1808,9 +1834,14 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m                  "unpacked tuple should have %s%zd elements,"                  " but has %zd",                  (min == max ? "" : "at most "), max, l); -        va_end(vargs);          return 0;      } + +#ifdef HAVE_STDARG_PROTOTYPES +    va_start(vargs, max); +#else +    va_start(vargs); +#endif      for (i = 0; i < l; i++) {          o = va_arg(vargs, PyObject **);          *o = PyTuple_GET_ITEM(args, i); | 
