]> granicus.if.org Git - python/commitdiff
Issue #9738: PyUnicode_FromFormat() and PyErr_Format() raise an error on
authorVictor Stinner <victor.stinner@haypocalc.com>
Sat, 11 Sep 2010 00:54:47 +0000 (00:54 +0000)
committerVictor Stinner <victor.stinner@haypocalc.com>
Sat, 11 Sep 2010 00:54:47 +0000 (00:54 +0000)
a non-ASCII byte in the format string.

Document also the encoding.

Doc/c-api/exceptions.rst
Doc/c-api/unicode.rst
Include/pyerrors.h
Include/unicodeobject.h
Lib/test/test_unicode.py
Misc/NEWS
Modules/_testcapimodule.c
Objects/unicodeobject.c

index fcbd50ba7ae6ddc72625abc8ce0948ad1a4e33f1..f969b967aeef7e4430c790fb11731c850915c7e9 100644 (file)
@@ -146,7 +146,7 @@ in various ways.  There is a separate error indicator for each thread.
 .. cfunction:: PyObject* PyErr_Format(PyObject *exception, const char *format, ...)
 
    This function sets the error indicator and returns *NULL*. *exception* should be
-   a Python exception (class, not an instance).  *format* should be a string,
+   a Python exception (class, not an instance). *format* should be an ASCII-encoded string,
    containing format codes, similar to :cfunc:`printf`. The ``width.precision``
    before a format code is parsed, but the width part is ignored.
 
index a4ee03abc0a224ab9fbd7bd71b8a35966cde39a2..1b8402c5d88dd60d392f412503fccc2a489cfd2e 100644 (file)
@@ -234,7 +234,7 @@ APIs:
    arguments, calculate the size of the resulting Python unicode string and return
    a string with the values formatted into it.  The variable arguments must be C
    types and must correspond exactly to the format characters in the *format*
-   string.  The following format characters are allowed:
+   ASCII-encoded string. The following format characters are allowed:
 
    .. % This should be exactly the same as the table in PyErr_Format.
    .. % The descriptions for %zd and %zu are wrong, but the truth is complicated
index 1eee16d2a87fb41be23d97f6659e35d4c05b8d53..243bc018daafd367a8fabf275743f7e47bbf31d5 100644 (file)
@@ -183,7 +183,11 @@ PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename(
     PyObject *, const Py_UNICODE *);
 #endif /* MS_WINDOWS */
 
-PyAPI_FUNC(PyObject *) PyErr_Format(PyObject *, const char *, ...);
+PyAPI_FUNC(PyObject *) PyErr_Format(
+    PyObject *exception,
+    const char *format,   /* ASCII-encoded string  */
+    ...
+    );
 
 #ifdef MS_WINDOWS
 PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilenameObject(
index 0de0d66d76b955c1b65ce2b9593007cb13a9d28e..820850ae01a300fd3b390238117e408d1a294e3d 100644 (file)
@@ -550,8 +550,14 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromObject(
     register PyObject *obj      /* Object */
     );
 
-PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV(const char*, va_list);
-PyAPI_FUNC(PyObject *) PyUnicode_FromFormat(const char*, ...);
+PyAPI_FUNC(PyObject *) PyUnicode_FromFormatV(
+    const char *format,   /* ASCII-encoded string  */
+    va_list vargs
+    );
+PyAPI_FUNC(PyObject *) PyUnicode_FromFormat(
+    const char *format,   /* ASCII-encoded string  */
+    ...
+    );
 
 /* Format the object based on the format_spec, as defined in PEP 3101
    (Advanced String Formatting). */
index ae5f53db6974d8363a4d252446480453e1093ebb..0c23daa83e8a30052cdc3a6f2f569a72725dfa32 100644 (file)
@@ -1385,6 +1385,20 @@ class UnicodeTest(string_tests.CommonTest,
         self.assertEquals("%s" % s, '__str__ overridden')
         self.assertEquals("{}".format(s), '__str__ overridden')
 
+    def test_from_format(self):
+        # Ensure that PyUnicode_FromFormat() raises an error for a non-ascii
+        # format string.
+        from _testcapi import format_unicode
+
+        # ascii format, non-ascii argument
+        text = format_unicode(b'ascii\x7f=%U', 'unicode\xe9')
+        self.assertEqual(text, 'ascii\x7f=unicode\xe9')
+
+        # non-ascii format, ascii argument
+        self.assertRaisesRegexp(ValueError,
+            '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format '
+            'string, got a non-ascii byte: 0xe9$',
+            format_unicode, b'unicode\xe9=%s', 'ascii')
 
 def test_main():
     support.run_unittest(__name__)
index 04eb82f568542f263132d3aeb089223dab10da0a..ca64883fd1a0ac23991d87e9d40b43dfa88cbe60 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ What's New in Python 3.2 Alpha 3?
 Core and Builtins
 -----------------
 
+- Issue #9738: PyUnicode_FromFormat() and PyErr_Format() raise an error on
+  a non-ASCII byte in the format string.
+
 - Issue #4617: Previously it was illegal to delete a name from the local
   namespace if it occurs as a free variable in a nested block.  This limitation
   of the compiler has been lifted, and a new opcode introduced (DELETE_DEREF).
index acbff344fe33773e097b917ccece3fd087672887..20887b17e8b7fc5c6e4408b1ccb0ee98bd551499 100644 (file)
@@ -2193,6 +2193,17 @@ crash_no_current_thread(PyObject *self)
     return NULL;
 }
 
+static PyObject *
+format_unicode(PyObject *self, PyObject *args)
+{
+    const char *format;
+    PyObject *arg;
+    if (!PyArg_ParseTuple(args, "yU", &format, &arg))
+        return NULL;
+    return PyUnicode_FromFormat(format, arg);
+
+}
+
 static PyMethodDef TestMethods[] = {
     {"raise_exception",         raise_exception,                 METH_VARARGS},
     {"raise_memoryerror",   (PyCFunction)raise_memoryerror,  METH_NOARGS},
@@ -2272,6 +2283,7 @@ static PyMethodDef TestMethods[] = {
     {"make_exception_with_doc", (PyCFunction)make_exception_with_doc,
      METH_VARARGS | METH_KEYWORDS},
     {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS},
+    {"format_unicode", format_unicode, METH_VARARGS},
     {NULL, NULL} /* sentinel */
 };
 
index 9cdf90d159c7dba47e08448959667bf34f4b641b..c010b1b246cff91c46c7ac7fadfd0a62ab2477c4 100644 (file)
@@ -1102,7 +1102,15 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
                 appendstring(p);
                 goto end;
             }
-        } else
+        }
+        else if (128 <= (unsigned char)*f) {
+            PyErr_Format(PyExc_ValueError,
+                "PyUnicode_FromFormatV() expects an ASCII-encoded format "
+                "string, got a non-ascii byte: 0x%02x",
+                (unsigned char)*f);
+            goto fail;
+        }
+        else
             *s++ = *f;
     }