Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] bpo-35059: Add assertion to _PyObject_CAST() #10649

Closed
wants to merge 1 commit into from
Closed

[WIP] bpo-35059: Add assertion to _PyObject_CAST() #10649

wants to merge 1 commit into from

Conversation

vstinner
Copy link
Member

@vstinner vstinner commented Nov 22, 2018

_PyObject_CAST() and _PyVarObject_CAST() macros now require that the
type of the argument has a size. For example, _PyObject_CAST(frame)
now raises a compilation error if frame type is "struct _frame*" but
"struct _frame" is not defined.

_PyObject_CAST() and _PyVarObject_CAST() macros now raise a
compilation error if the argument is a "PyObject" or a "PyObject**".

Partially revert b37672d to show
that _PyObject_CAST() accepts non-trivial expressions.

https://bugs.python.org/issue35059

@vstinner
Copy link
Member Author

vstinner commented Nov 22, 2018

This change introduces two backward incompatible changes:

  • _PyObject_CAST(keyfile ? keyfile_bytes : certfile_bytes) raises a compilation error, whereas it's legit code and works if Py_TYPE() is a regular function.
  • _PyObject_CAST(frame) raises a compilation error if frame type is undefined. Example: struct _frame * without "frameobject.h".

See my commit b37672d for other examples of regressions.

So I don't think that this change should be merged.

@vstinner vstinner requested a review from 1st1 as a code owner November 22, 2018 08:09
Include/object.h Outdated
const char *func(PyObject *item) { return Py_TYPE(&item)->tp_name; }
*/
#define _PyObject_CAST(op) \
((PyObject*)(op) + Py_BUILD_ASSERT_EXPR(sizeof(*op) != sizeof(op)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if op is an expression, then your dereferencing is likely to fail, better use *(op).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And you don't have the issue of op being evaluated three times because sizeof does not evaluate the expression \o/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, fixed.

_PyObject_CAST() and _PyVarObject_CAST() macros now require that the
type of the argument has a size. For example, _PyObject_CAST(frame)
now raises a compilation error if frame type is "struct _frame*" but
"struct _frame" is not defined.

_PyObject_CAST() and _PyVarObject_CAST() macros now raise a
compilation error if the argument is a "PyObject" or a "PyObject**".

Partially revert b37672d to show
that _PyObject_CAST() accepts non-trivial expressions.
@vstinner
Copy link
Member Author

_PyObject_CAST() and _PyVarObject_CAST() macros now require that the
type of the argument has a size. For example, _PyObject_CAST(frame)
now raises a compilation error if frame type is "struct _frame*" but
"struct _frame" is not defined.

IMHO it's a blocker issue, it's a backward incompatible change.

At least, _PyObject_CAST() doesn't require 'op' to have a size of Py_LIMITED_API is defined.

@vstinner
Copy link
Member Author

cc @nascheme: you might like this experiment :-)

@vstinner
Copy link
Member Author

@serhiy-storchaka, @pablogsal: I experimented a C macro to detect "Py_TYPE(&obj)" bug (with "PyObject *obj"), but it doesn't seem possible to write a magic macro because the Python C API is a mess :-)

For example, _PyObject_CAST() should also accept PyTupleObject* which contains a "PyObject ob_base". But there are other type monsters like:

  • PyASCIIObject: PyObject ob_base;
  • PyCompactUnicodeObject: PyASCIIObject _base;
  • PyUnicodeObject: PyCompactUnicodeObject _base;

@serhiy-storchaka
Copy link
Member

I did not know about _PyObject_CAST().

@vstinner
Copy link
Member Author

I did not know about _PyObject_CAST()

I added it yesterday :-) commit 2ff8fb7

I wrote it for C macros to avoid "(PyObject*)ob" mistake: missing parenthesis around "ob". By the way, I should fix Include/odictobject.h in Python 3.6 and 3.7.

I have to confess that I also wrote the macro to be able to make such experiment. More generally, it's a hint on cast between object pointer types which helps me on my work on the C API.

@vstinner
Copy link
Member Author

Ok, this PR was fun to write, but since it's breaking the backward compatibility, it's really a no-go and so I close it.

@vstinner vstinner closed this Nov 22, 2018
@vstinner vstinner deleted the cast_assert branch November 22, 2018 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants