| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 79db9d9 commit 633ea21
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,9 +1,12 @@ | |||
| 1 | + import errno | ||
| 2 | + import os | ||
| 1 | 3 | import re | |
| 2 | 4 | import sys | |
| 3 | 5 | import unittest | |
| 4 | 6 | ||
| 5 | 7 | from test import support | |
| 6 | 8 | from test.support import import_helper | |
| 9 | + from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE | ||
| 7 | 10 | from test.support.script_helper import assert_python_failure | |
| 8 | 11 | from test.support.testcase import ExceptionIsLikeMixin | |
| 9 | 12 | ||
@@ -12,6 +15,8 @@ | |||
| 12 | 15 | # Skip this test if the _testcapi module isn't available. | |
| 13 | 16 | _testcapi = import_helper.import_module('_testcapi') | |
| 14 | 17 | ||
| 18 | + NULL = None | ||
| 19 | + | ||
| 15 | 20 | class Test_Exceptions(unittest.TestCase): | |
| 16 | 21 | ||
| 17 | 22 | def test_exception(self): | |
@@ -189,6 +194,82 @@ def __repr__(self): | |||
| 189 | 194 | self.assertEqual(exc.__notes__[0], | |
| 190 | 195 | 'Normalization failed: type=Broken args=<unknown>') | |
| 191 | 196 | ||
| 197 | + def test_set_string(self): | ||
| 198 | + """Test PyErr_SetString()""" | ||
| 199 | + setstring = _testcapi.err_setstring | ||
| 200 | + with self.assertRaises(ZeroDivisionError) as e: | ||
| 201 | + setstring(ZeroDivisionError, b'error') | ||
| 202 | + self.assertEqual(e.exception.args, ('error',)) | ||
| 203 | + with self.assertRaises(ZeroDivisionError) as e: | ||
| 204 | + setstring(ZeroDivisionError, 'помилка'.encode()) | ||
| 205 | + self.assertEqual(e.exception.args, ('помилка',)) | ||
| 206 | + | ||
| 207 | + with self.assertRaises(UnicodeDecodeError): | ||
| 208 | + setstring(ZeroDivisionError, b'\xff') | ||
| 209 | + self.assertRaises(SystemError, setstring, list, b'error') | ||
| 210 | + # CRASHES setstring(ZeroDivisionError, NULL) | ||
| 211 | + # CRASHES setstring(NULL, b'error') | ||
| 212 | + | ||
| 213 | + def test_format(self): | ||
| 214 | + """Test PyErr_Format()""" | ||
| 215 | + import_helper.import_module('ctypes') | ||
| 216 | + from ctypes import pythonapi, py_object, c_char_p, c_int | ||
| 217 | + name = "PyErr_Format" | ||
| 218 | + PyErr_Format = getattr(pythonapi, name) | ||
| 219 | + PyErr_Format.argtypes = (py_object, c_char_p,) | ||
| 220 | + PyErr_Format.restype = py_object | ||
| 221 | + with self.assertRaises(ZeroDivisionError) as e: | ||
| 222 | + PyErr_Format(ZeroDivisionError, b'%s %d', b'error', c_int(42)) | ||
| 223 | + self.assertEqual(e.exception.args, ('error 42',)) | ||
| 224 | + with self.assertRaises(ZeroDivisionError) as e: | ||
| 225 | + PyErr_Format(ZeroDivisionError, b'%s', 'помилка'.encode()) | ||
| 226 | + self.assertEqual(e.exception.args, ('помилка',)) | ||
| 227 | + | ||
| 228 | + with self.assertRaisesRegex(OverflowError, 'not in range'): | ||
| 229 | + PyErr_Format(ZeroDivisionError, b'%c', c_int(-1)) | ||
| 230 | + with self.assertRaisesRegex(ValueError, 'format string'): | ||
| 231 | + PyErr_Format(ZeroDivisionError, b'\xff') | ||
| 232 | + self.assertRaises(SystemError, PyErr_Format, list, b'error') | ||
| 233 | + # CRASHES PyErr_Format(ZeroDivisionError, NULL) | ||
| 234 | + # CRASHES PyErr_Format(py_object(), b'error') | ||
| 235 | + | ||
| 236 | + def test_setfromerrnowithfilename(self): | ||
| 237 | + """Test PyErr_SetFromErrnoWithFilename()""" | ||
| 238 | + setfromerrnowithfilename = _testcapi.err_setfromerrnowithfilename | ||
| 239 | + ENOENT = errno.ENOENT | ||
| 240 | + with self.assertRaises(FileNotFoundError) as e: | ||
| 241 | + setfromerrnowithfilename(ENOENT, OSError, b'file') | ||
| 242 | + self.assertEqual(e.exception.args, | ||
| 243 | + (ENOENT, 'No such file or directory')) | ||
| 244 | + self.assertEqual(e.exception.errno, ENOENT) | ||
| 245 | + self.assertEqual(e.exception.filename, 'file') | ||
| 246 | + | ||
| 247 | + with self.assertRaises(FileNotFoundError) as e: | ||
| 248 | + setfromerrnowithfilename(ENOENT, OSError, os.fsencode(TESTFN)) | ||
| 249 | + self.assertEqual(e.exception.filename, TESTFN) | ||
| 250 | + | ||
| 251 | + if TESTFN_UNDECODABLE: | ||
| 252 | + with self.assertRaises(FileNotFoundError) as e: | ||
| 253 | + setfromerrnowithfilename(ENOENT, OSError, TESTFN_UNDECODABLE) | ||
| 254 | + self.assertEqual(e.exception.filename, | ||
| 255 | + os.fsdecode(TESTFN_UNDECODABLE)) | ||
| 256 | + | ||
| 257 | + with self.assertRaises(FileNotFoundError) as e: | ||
| 258 | + setfromerrnowithfilename(ENOENT, OSError, NULL) | ||
| 259 | + self.assertIsNone(e.exception.filename) | ||
| 260 | + | ||
| 261 | + with self.assertRaises(OSError) as e: | ||
| 262 | + setfromerrnowithfilename(0, OSError, b'file') | ||
| 263 | + self.assertEqual(e.exception.args, (0, 'Error')) | ||
| 264 | + self.assertEqual(e.exception.errno, 0) | ||
| 265 | + self.assertEqual(e.exception.filename, 'file') | ||
| 266 | + | ||
| 267 | + with self.assertRaises(ZeroDivisionError) as e: | ||
| 268 | + setfromerrnowithfilename(ENOENT, ZeroDivisionError, b'file') | ||
| 269 | + self.assertEqual(e.exception.args, | ||
| 270 | + (ENOENT, 'No such file or directory', 'file')) | ||
| 271 | + # CRASHES setfromerrnowithfilename(ENOENT, NULL, b'error') | ||
| 272 | + | ||
| 192 | 273 | ||
| 193 | 274 | class Test_PyUnstable_Exc_PrepReraiseStar(ExceptionIsLikeMixin, unittest.TestCase): | |
| 194 | 275 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + Such C API functions as ``PyErr_SetString()``, ``PyErr_Format()``, | ||
| 2 | + ``PyErr_SetFromErrnoWithFilename()`` and many others no longer crash or | ||
| 3 | + ignore errors if it failed to format the error message or decode the | ||
| 4 | + filename. Instead, they keep a corresponding error. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,6 +1,8 @@ | |||
| 1 | 1 | #include "parts.h" | |
| 2 | 2 | #include "clinic/exceptions.c.h" | |
| 3 | 3 | ||
| 4 | + #define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); | ||
| 5 | + | ||
| 4 | 6 | /*[clinic input] | |
| 5 | 7 | module _testcapi | |
| 6 | 8 | [clinic start generated code]*/ | |
@@ -129,6 +131,43 @@ _testcapi_exc_set_object_fetch_impl(PyObject *module, PyObject *exc, | |||
| 129 | 131 | return value; | |
| 130 | 132 | } | |
| 131 | 133 | ||
| 134 | + /*[clinic input] | ||
| 135 | + _testcapi.err_setstring | ||
| 136 | + exc: object | ||
| 137 | + value: str(zeroes=True, accept={robuffer, str, NoneType}) | ||
| 138 | + / | ||
| 139 | + [clinic start generated code]*/ | ||
| 140 | + | ||
| 141 | + static PyObject * | ||
| 142 | + _testcapi_err_setstring_impl(PyObject *module, PyObject *exc, | ||
| 143 | + const char *value, Py_ssize_t value_length) | ||
| 144 | + /*[clinic end generated code: output=fba8705e5703dd3f input=e8a95fad66d9004b]*/ | ||
| 145 | + { | ||
| 146 | + NULLABLE(exc); | ||
| 147 | + PyErr_SetString(exc, value); | ||
| 148 | + return NULL; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + /*[clinic input] | ||
| 152 | + _testcapi.err_setfromerrnowithfilename | ||
| 153 | + error: int | ||
| 154 | + exc: object | ||
| 155 | + value: str(zeroes=True, accept={robuffer, str, NoneType}) | ||
| 156 | + / | ||
| 157 | + [clinic start generated code]*/ | ||
| 158 | + | ||
| 159 | + static PyObject * | ||
| 160 | + _testcapi_err_setfromerrnowithfilename_impl(PyObject *module, int error, | ||
| 161 | + PyObject *exc, const char *value, | ||
| 162 | + Py_ssize_t value_length) | ||
| 163 | + /*[clinic end generated code: output=d02df5749a01850e input=ff7c384234bf097f]*/ | ||
| 164 | + { | ||
| 165 | + NULLABLE(exc); | ||
| 166 | + errno = error; | ||
| 167 | + PyErr_SetFromErrnoWithFilename(exc, value); | ||
| 168 | + return NULL; | ||
| 169 | + } | ||
| 170 | + | ||
| 132 | 171 | /*[clinic input] | |
| 133 | 172 | _testcapi.raise_exception | |
| 134 | 173 | exception as exc: object | |
@@ -338,6 +377,8 @@ static PyMethodDef test_methods[] = { | |||
| 338 | 377 | _TESTCAPI_MAKE_EXCEPTION_WITH_DOC_METHODDEF | |
| 339 | 378 | _TESTCAPI_EXC_SET_OBJECT_METHODDEF | |
| 340 | 379 | _TESTCAPI_EXC_SET_OBJECT_FETCH_METHODDEF | |
| 380 | + _TESTCAPI_ERR_SETSTRING_METHODDEF | ||
| 381 | + _TESTCAPI_ERR_SETFROMERRNOWITHFILENAME_METHODDEF | ||
| 341 | 382 | _TESTCAPI_RAISE_EXCEPTION_METHODDEF | |
| 342 | 383 | _TESTCAPI_RAISE_MEMORYERROR_METHODDEF | |
| 343 | 384 | _TESTCAPI_SET_EXC_INFO_METHODDEF | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -292,8 +292,10 @@ _PyErr_SetString(PyThreadState *tstate, PyObject *exception, | |||
| 292 | 292 | const char *string) | |
| 293 | 293 | { | |
| 294 | 294 | PyObject *value = PyUnicode_FromString(string); | |
| 295 | - _PyErr_SetObject(tstate, exception, value); | ||
| 296 | - Py_XDECREF(value); | ||
| 295 | + if (value != NULL) { | ||
| 296 | + _PyErr_SetObject(tstate, exception, value); | ||
| 297 | + Py_DECREF(value); | ||
| 298 | + } | ||
| 297 | 299 | } | |
| 298 | 300 | ||
| 299 | 301 | void | |
@@ -891,7 +893,13 @@ PyErr_SetFromErrnoWithFilenameObjects(PyObject *exc, PyObject *filenameObject, P | |||
| 891 | 893 | PyObject * | |
| 892 | 894 | PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename) | |
| 893 | 895 | { | |
| 894 | - PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; | ||
| 896 | + PyObject *name = NULL; | ||
| 897 | + if (filename) { | ||
| 898 | + name = PyUnicode_DecodeFSDefault(filename); | ||
| 899 | + if (name == NULL) { | ||
| 900 | + return NULL; | ||
| 901 | + } | ||
| 902 | + } | ||
| 895 | 903 | PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, NULL); | |
| 896 | 904 | Py_XDECREF(name); | |
| 897 | 905 | return result; | |
@@ -988,7 +996,13 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename( | |||
| 988 | 996 | int ierr, | |
| 989 | 997 | const char *filename) | |
| 990 | 998 | { | |
| 991 | - PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; | ||
| 999 | + PyObject *name = NULL; | ||
| 1000 | + if (filename) { | ||
| 1001 | + name = PyUnicode_DecodeFSDefault(filename); | ||
| 1002 | + if (name == NULL) { | ||
| 1003 | + return NULL; | ||
| 1004 | + } | ||
| 1005 | + } | ||
| 992 | 1006 | PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc, | |
| 993 | 1007 | ierr, | |
| 994 | 1008 | name, | |
@@ -1012,7 +1026,13 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( | |||
| 1012 | 1026 | int ierr, | |
| 1013 | 1027 | const char *filename) | |
| 1014 | 1028 | { | |
| 1015 | - PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; | ||
| 1029 | + PyObject *name = NULL; | ||
| 1030 | + if (filename) { | ||
| 1031 | + name = PyUnicode_DecodeFSDefault(filename); | ||
| 1032 | + if (name == NULL) { | ||
| 1033 | + return NULL; | ||
| 1034 | + } | ||
| 1035 | + } | ||
| 1016 | 1036 | PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects( | |
| 1017 | 1037 | PyExc_OSError, | |
| 1018 | 1038 | ierr, name, NULL); | |
@@ -1137,9 +1157,10 @@ _PyErr_FormatV(PyThreadState *tstate, PyObject *exception, | |||
| 1137 | 1157 | _PyErr_Clear(tstate); | |
| 1138 | 1158 | ||
| 1139 | 1159 | string = PyUnicode_FromFormatV(format, vargs); | |
| 1140 | - | ||
| 1141 | - _PyErr_SetObject(tstate, exception, string); | ||
| 1142 | - Py_XDECREF(string); | ||
| 1160 | + if (string != NULL) { | ||
| 1161 | + _PyErr_SetObject(tstate, exception, string); | ||
| 1162 | + Py_DECREF(string); | ||
| 1163 | + } | ||
| 1143 | 1164 | return NULL; | |
| 1144 | 1165 | } | |
| 1145 | 1166 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments