Repository navigation
Check that _PyUnicode_AsString() result is not NULL #50946
Copy link
Copy link
Closed
Labels
OS-macinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-unicodetype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Description
| BPO | 6697 |
|---|---|
| Nosy | @malemburg, @loewis, @ronaldoussoren, @amauryfa, @abalkin, @vstinner, @ezio-melotti |
| Files |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = 'https://github.com/abalkin'
closed_at = <Date 2011-06-20.13:08:04.113>
created_at = <Date 2009-08-13.20:07:31.030>
labels = ['OS-mac', 'interpreter-core', 'expert-unicode', 'type-crash']
title = 'Check that _PyUnicode_AsString() result is not NULL'
updated_at = <Date 2011-06-20.13:08:04.112>
user = 'https://bugs.python.org/Arfrever'bugs.python.org fields:
activity = <Date 2011-06-20.13:08:04.112>
actor = 'vstinner'
assignee = 'belopolsky'
closed = True
closed_date = <Date 2011-06-20.13:08:04.113>
closer = 'vstinner'
components = ['Interpreter Core', 'macOS', 'Unicode']
creation = <Date 2009-08-13.20:07:31.030>
creator = 'Arfrever'
dependencies = []
files = ['14711', '14713', '19958', '19970', '19972', '20397']
hgrepos = []
issue_num = 6697
keywords = ['patch', 'needs review']
message_count = 48.0
messages = ['91533', '91534', '91576', '91727', '91728', '91730', '91731', '91732', '91742', '100445', '100446', '100468', '100474', '100476', '100680', '100683', '100946', '100947', '100948', '101458', '105892', '105893', '106016', '106019', '106020', '106021', '106022', '106023', '106024', '106058', '123473', '123474', '123479', '123482', '123566', '123568', '123573', '123574', '123575', '123577', '123582', '123662', '123664', '123767', '126216', '126221', '138705', '138706']
nosy_count = 10.0
nosy_names = ['lemburg', 'loewis', 'jafo', 'ronaldoussoren', 'amaury.forgeotdarc', 'belopolsky', 'vstinner', 'ezio.melotti', 'Arfrever', 'python-dev']
pr_nums = []
priority = 'high'
resolution = 'fixed'
stage = 'commit review'
status = 'closed'
superseder = None
type = 'crash'
url = 'https://bugs.python.org/issue6697'
versions = ['Python 3.2', 'Python 3.3']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
OS-macinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-unicodetype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
Activity
Arfrever commentedon Aug 13, 2009
Python 3.1 segfaults when invalid UTF-8 characters are passed from
command line.
In BASH shell you can run:
$ python3.1 -c $'print("\x80")'
Segmentation fault
In other POSIX-compatible shells you can save the attached test.py
files in current directory and run:
$ python3.1 -c "$(<test.py)"
Segmentation fault
Arfrever commentedon Aug 13, 2009
I'm attaching crashers/invalid_utf8_characters_from_command_line.py.
vstinner commentedon Aug 14, 2009
The error occurs in Py_Main(), on _PyUnicode_AsString(commandObj). The
problem is that _PyUnicode_AsString() is not checked for error. Here is
a patch fixing two errors:
_PyUnicode_AsString(commandObj) failure
(PyUnicode_FromWideChar error, a different error)
My patch also includes a test. The test should be moved somewhere else,
but I don't know where.
amauryfa commentedon Aug 19, 2009
The problem is actually wider:: >>> getattr(None, "\udc80") Segmentation fault An idea would be to change _PyUnicode_AsDefaultEncodedString and allow unpaired surrogates (utf8+surrogateescape, as explained in PEP383), but I fear the consequences...The code that fails seems pretty common:
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%.400s'",
tp->tp_name, _PyUnicode_AsString(name));
It would be unfortunate to replace all usages of _PyUnicode_AsString to
check the return value.
Martin, what do you think?
malemburg commentedon Aug 19, 2009
The use of _PyUnicode_AsString() is wrong here. There are several
cases where it can fail, e.g. MemoryErrors, embedded NULs, encoding
errors.
The same is true for _PyUnicode_AsStringAndSize(), which is why
I turned them into Python interpreter private APIs before 3.0
shipped.
If you want a fail-safe stringified version of a Unicode object,
your only choice is to create a new API that does error checking,
properly clears the error and then returns a reference to a constant
string, e.g. "<repr-error>".
[-]Python 3.1 segfaults when invalid UTF-8 characters are passed from command line[/-][+]Python 3.1 segfaults when invalid UTF-8 characters are passed from command line[/+]amauryfa commentedon Aug 19, 2009
Do you suggest to remove all usages of _PyUnicode_AsString() and
_PyUnicode_AsStringAndSize()?
malemburg commentedon Aug 19, 2009
Amaury Forgeot d'Arc wrote:
In the short-term, I suggest that all uses that do not check the
return value get replaced with a new API which implements a failsafe
return value strategy.
In the mid- to long-term, the APIs should probably be removed
altogether.
They look a lot like the PyString APIs using the same names, but unlike
those APIs, they can fail, so the implied straight-forward conversion
of the PyString APIs to the above APIs gives a wrong impression to the
developers.
For error messages, I'd use the repr() of the objects - lone UTF-8
surrogates will not work since they cause issues further down the line
with debugging tools or even stderr terminal displays.
amauryfa commentedon Aug 19, 2009
The %U format seems adequate for this purpose - actually
PyObject_GenericSetAttr uses it already.
Yes, the exception message will contain the same lone UTF-8
surrogates; this is not a problem because sys.stderr uses the
"backslashreplace" error handler.
loewis commentedon Aug 19, 2009
I agree with MAL: we do need to check for errors returned from
_PyUnicode_AsString, and it would be best if we created a fail-safe
version of it.
In the specific case (getattr), it might also be useful to create a
result that is unicode-escaped, i.e. with \u escapes for all non-ASCII
non-printable characters.
For _PyUnicode_AsString, I'm uncertain whether supporting half
surrogates is a good idea. Unless there is a compelling reason to
support them, I think we leave that as-is. Your example is not
compelling: I think the unicode string should be escaped, anyway.
The OP's case is also not compelling, we should print an error
message that the source code is incorrectly encoded.
vstinner commentedon Mar 5, 2010
Here is a fix for object.c (object_pyunicode_asstring-py3k.patch):
It fixes the crash getattr(1, "\uDAD1\uD51E") (used as a test in the patch).
[-]Python 3.1 segfaults when invalid UTF-8 characters are passed from command line[/-][+]Check that _PyUnicode_AsString() result is not NULL[/+]29 remaining items
malemburg commentedon Dec 7, 2010
Alexander Belopolsky wrote:
Some notes:
Rather than just patching in error handling code, please consider
removing use of those APIs and replace their calls with something
more appropriate, e.g. using a parser API.
When ignoring errors from the API, you have to clear the exception.
This is missing in a couple of places in the patch, e.g. in pyexpat.c
Please also remove hacks like these:
+#define CMP PyUnicode_CompareWithASCIIString
+ if (CMP(nameobj, "entity") == 0)
+ res = self->entity;
+ else if (CMP(nameobj, "target") == 0)
+ res = self->target;
+ else if (CMP(nameobj, "version") == 0) {
+ return PyUnicode_FromFormat(
+ "Expat %d.%d.%d", XML_MAJOR_VERSION,
XML_MINOR_VERSION, XML_MICRO_VERSION);
abalkin commentedon Dec 7, 2010
On Tue, Dec 7, 2010 at 12:44 PM, Marc-Andre Lemburg
<report@bugs.python.org> wrote:
..
Yes, that's what I started doing in the "a" patch. I am not sure what
you mean by "a parser API." There are several places where conversion
is either unnecessary or an encoded string is already available. See
_elementtree.c.
Right. On the other hand, this is very similar to xmlparser_getattro
in _elementtree.c and I think should be handled the same way.
What do you consider a hack? The use of
PyUnicode_CompareWithASCIIString() or the shortening macro?
malemburg commentedon Dec 7, 2010
Alexander Belopolsky wrote:
PyArg_Parse() et al. See the discussion earlier on this ticket.
If the API is not needed at all, even better.
Not sure what you mean here. If you ignore errors and don't clear
the exception, it will pop up at some later point in processing
and that's generally very confusing.
The shortening macro.
abalkin commentedon Dec 7, 2010
On Tue, Dec 7, 2010 at 1:11 PM, Marc-Andre Lemburg
<report@bugs.python.org> wrote:
I've just realized that. It is the "u#" code. Yes, I'll see if I can
use it instead of "U", but I think in the affected code the PyUnicode
object is needed as well.
I mean not converting to char* at all and use
PyUnicode_CompareWithASCIIString() instead of strcmp(). I wish that
function had a shorter name, though, but it is not a big deal to spell
it out. BTW, I don't think there is a way to use wchar_t* literals in
Python code, right? As in Py_UNICODE_strcmp(name, L"version").
malemburg commentedon Dec 7, 2010
Agreed; not my invention ;-) I would have used
PyUnicode_CompareToUTF8() or something along those lines.
No, since wchar_t may be something completely different than
Py_UNICODE.
No sure about today's situation, but at least a couple of years
ago wchar_t was not defined on all supported platforms, e.g.
Crays didn't have it.
abalkin commentedon Dec 7, 2010
issue6697b.diff addresses Marc's comments. Thanks for the review.
abalkin commentedon Dec 8, 2010
Committed revision 87137. Needs backporting. Also as Victor suggested, _lsprof.c code can be refactored to avoid roundtrips of unicode through utf8 char*.
abalkin commentedon Dec 9, 2010
I am attaching an untested rewrite of normalizeUserObj() in _lsprof.c for comments on whether it is worth the effort. There might be other places where PyModule_GetName() can be profitably replaced with PyModule_GetNameObject().
vstinner commentedon Dec 11, 2010
bpo-6697-lsprof.diff:
abalkin commentedon Jan 13, 2011
I am replacing bpo-6697-lsprof.diff with a (hopefully) more carefully written version that addresses the issues that Victor noted.
Victor,
I take your comment as +1 for adding PyModule_GetNameObject().
I started looking into adding unit tests that would exercise this code, but is does not seem possible to trigger the fn->m_self == NULL condition. According to the comment in the code, this is supposed to be the case when fn is a builtin function, but I observe the following in the debugger when running test_cprofile:
(gdb) pyo fn
object : <built-in function exec>
type : builtin_function_or_method
refcount: 4
address : 0x10038c678
$5 = void
(gdb) pyo fn->m_self
object : <module 'builtins' (built-in)>
type : module
refcount: 51
address : 0x100388ee8
$6 = void
vstinner commentedon Jan 14, 2011
Le jeudi 13 janvier 2011 à 23:05 +0000, Alexander Belopolsky a écrit :
I wrote a similar patch to add PyModule_GetNameObject() (I am working on
another huge patch, to fix bpo-3080). You have to document the new function
in Doc/c-api/module.rst.
Yes, it's better to work on unicode than encode unicode to bytes
(PyModule_GetName() with UTF-8) and then decode bytes from unicode
(PyUnicode_FromFormat with %s).
I am too tired to review the patch.
python-dev commentedon Jun 20, 2011
New changeset b87eac0369b5 by Victor Stinner in branch 'default':
Issue bpo-6697: _lsprof: normalizeUserObj() doesn't encode/decode (UTF-8) the
http://hg.python.org/cpython/rev/b87eac0369b5
vstinner commentedon Jun 20, 2011
Issue bpo-3080 added the PyModule_GetNameObject() function, so it simplify your patch.
I commited your bpo-6697-lsprof.diff patch, I just fixed a refleak (if modname is "builtins").
I want to close this generic issue. I think that we fixed enough code. If you still see code not checking that _PyUnicode_AsString() result is not NULL, please open a new specific issue.