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

bpo-29941: Assert fixes #886

Merged
merged 4 commits into from
Mar 31, 2017
Merged

bpo-29941: Assert fixes #886

merged 4 commits into from
Mar 31, 2017

Conversation

Yhg1s
Copy link
Member

@Yhg1s Yhg1s commented Mar 29, 2017

There is a bit of confusion in the CPython source between Py_DEBUG and (C) asserts. By default Python builds without Py_DEBUG and without asserts (definining NDEBUG to disable them). Turning on Py_DEBUG also enables asserts. However, it is possible to turn on asserts without turning on Py_DEBUG, and at Google we routinely build CPython that way. (Doing this with the regular configure/make process can be done by setting CFLAGS=-UNDEBUG when running configure.) This happens to highlight two different problems:

  • Code being defined in Py_DEBUG blocks but used in assertions: _PyDict_CheckConsistency() is defined in dictobject.c in an #ifdef Py_DEBUG, but then used in assert without a check for Py_DEBUG. This is a compile-time error.

  • Assertions checking for things that are outside of CPython's control, like whether an exception is set before calling something that might clobber it. Generally speaking assertions should be for internal invariants; things that should be a specific way, and it's an error in CPython itself when it's not (I think Tim Peters originally expressed this view of C asserts). For example, PyObject_Call() (and various other flavours of it) does assert(!PyErr_Occurred()), which is easily triggered and the cause of which is not always apparent.

The second case is useful, mind you, as it exposes bugs in extension modules, but the way it does it is not very helpful (it displays no traceback), and if the intent is to only do this when Py_DEBUG is enabled it would be better to check for that. This PR fixes both issues.

I think what our codebase does (enable assertions by default, without enabling Py_DEBUG) is useful, even when applied to CPython, and I would like CPython to keep working that way. However, if it's deemed more appropriate to make assertions only work in Py_DEBUG mode, that's fine too -- but please make it explicit, by making non-Py_DEBUG builds require NDEBUG.

…means

making sure helper functions are defiend when NDEBUG is not defined, not
just when Py_DEBUG is defined.

Also fix a division-by-zero in obmalloc.c: in Py_DEBUG mode, elsize is never
0, so this assert is never triggered.
…Unlike

other asserts this is easy to trigger indirectly, and the assertion failure
will not point to the actual problem.
@mention-bot
Copy link

@Yhg1s, thanks for your PR! By analyzing the history of the files in this pull request, we identified @benjaminp, @serhiy-storchaka and @tim-one to be potential reviewers.

@serhiy-storchaka serhiy-storchaka changed the title Assert fixes bpo-29941: Assert fixes Mar 29, 2017
Copy link
Contributor

@benjaminp benjaminp left a comment

Choose a reason for hiding this comment

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

I support making assertions without Py_DEBUG work. We should add an easy way to do this with --configure and add a buildbot for it.

It seems like many of your changes would be simplified if there was a Py_DEBUG_ASSERT macro.

@@ -1227,7 +1227,7 @@ _PyObject_Alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)

_Py_AllocatedBlocks++;

assert(nelem <= PY_SSIZE_T_MAX / elsize);
assert(elsize == 0 || nelem <= PY_SSIZE_T_MAX / elsize);
nbytes = nelem * elsize;
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably this whole block should go under after line 1242 instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved line 1242 up instead.

@Yhg1s
Copy link
Member Author

Yhg1s commented Mar 30, 2017

Dropped the change to add Py_DEBUG guards around dubious asserts, as Tim doesn't think the're dubious enough :)

@brettcannon brettcannon added the type-bug An unexpected behavior, bug, or error label Mar 30, 2017
@Yhg1s Yhg1s merged commit a00c3fd into python:master Mar 31, 2017
@Yhg1s Yhg1s deleted the assert-fixes branch March 31, 2017 16:14
@Yhg1s Yhg1s restored the assert-fixes branch March 31, 2017 16:37
Yhg1s added a commit that referenced this pull request Mar 31, 2017
Yhg1s added a commit to Yhg1s/cpython that referenced this pull request Mar 31, 2017
Yhg1s added a commit that referenced this pull request Mar 31, 2017
Fix MemoryError caused by moving around code in PR #886; nbytes was sometimes used unitinitalized (in non-debug builds, when use_calloc was false and elsize was 0).
Yhg1s added a commit to Yhg1s/cpython that referenced this pull request Mar 31, 2017
Make a non-Py_DEBUG, asserts-enabled build of CPython possible. This means
making sure helper functions are defined when NDEBUG is not defined, not
just when Py_DEBUG is defined.

Also fix a division-by-zero in obmalloc.c that went unnoticed because in
Py_DEBUG mode, elsize is never zero.

(cherry picked from commit a00c3fd and 06bb487)
Yhg1s added a commit to Yhg1s/cpython that referenced this pull request Mar 31, 2017
Make a non-Py_DEBUG, asserts-enabled build of CPython possible. This means
making sure helper functions are defined when NDEBUG is not defined, not
just when Py_DEBUG is defined.

Also fix a division-by-zero in obmalloc.c that went unnoticed because in
Py_DEBUG mode, elsize is never zero.

(cherry picked from commit a00c3fd and 06bb487)
@Yhg1s Yhg1s deleted the assert-fixes branch March 31, 2017 19:57
@vstinner
Copy link
Member

I wrote most _PyXXX_CheckConsistency() methods. To be clear: these methods are not written for performances, but to catch bugs earlier. Be careful on slowdown if you enable assertions on production ;-)

@Yhg1s
Copy link
Member Author

Yhg1s commented Mar 31, 2017

We enable them for tests (which we run a lot, all the time, but that's okay), not for deployed code.

Yhg1s added a commit to Yhg1s/cpython that referenced this pull request Apr 1, 2017
Make a non-Py_DEBUG, asserts-enabled build of CPython possible. This means
making sure helper functions are defined when NDEBUG is not defined, not
just when Py_DEBUG is defined.

Also fix a division-by-zero in obmalloc.c that went unnoticed because in
Py_DEBUG mode, elsize is never zero.

(cherry picked from commit a00c3fd and 06bb487)
Yhg1s added a commit that referenced this pull request Apr 2, 2017
Make a non-Py_DEBUG, asserts-enabled build of CPython possible. This means
making sure helper functions are defined when NDEBUG is not defined, not
just when Py_DEBUG is defined.

Also fix a division-by-zero in obmalloc.c that went unnoticed because in
Py_DEBUG mode, elsize is never zero.

(cherry picked from commit a00c3fd and 06bb487)
Yhg1s added a commit that referenced this pull request Apr 2, 2017
Make a non-Py_DEBUG, asserts-enabled build of CPython possible. This means
making sure helper functions are defined when NDEBUG is not defined, not
just when Py_DEBUG is defined.

Also fix a division-by-zero in obmalloc.c that went unnoticed because in
Py_DEBUG mode, elsize is never zero.

(cherry picked from commit a00c3fd and 06bb487)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants