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: Debugging mode for CPython universal #43

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions hpy/universal/src/debugmode.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <execinfo.h>
#include "debugmode.h"


#define BT_BUF_SIZE 25

void
_hpy_fatal(const char *msg, ...)
{
void *buffer[BT_BUF_SIZE];
int nptrs;

fprintf(stderr,
"------------------------------------------------------------\n"
"Fatal error in HPy (most recent call first):\n");
nptrs = backtrace(buffer, BT_BUF_SIZE);
backtrace_symbols_fd(buffer, nptrs, /*fd=*/ 2);

va_list ap;
va_start(ap, msg);
vfprintf(stderr, msg, ap);
va_end(ap);
fprintf(stderr,
"\n"
"------------------------------------------------------------\n");

abort();
}
12 changes: 12 additions & 0 deletions hpy/universal/src/debugmode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef HPY_DEBUGMODE_H
#define HPY_DEBUGMODE_H

void _hpy_fatal(const char *msg, ...);

#define HPY_ASSERT(condition, errargs) \
do { \
if (!(condition)) \
_hpy_fatal errargs; \
Copy link
Collaborator

Choose a reason for hiding this comment

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

we can probably use __VA_ARGS__ to avoid the weird usage pattern in which you have to put parenthesis in the call?

} while (0)

#endif /* HPY_DEBUGMODE_H */
45 changes: 40 additions & 5 deletions hpy/universal/src/handles.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,28 @@
#include <stdlib.h>
#include "hpy.h"
#include "handles.h"
#include "debugmode.h"


/* XXX we should turn the fast-path of _py2h and _h2py into macros in api.h */

static PyObject **all_handles;
static Py_ssize_t h_num_allocated = 0;
static Py_ssize_t h_free_list = -1;
static Py_ssize_t h_free_list_2 = -1;
/* note: h_free_list_2 is only here for debugging. We can push freed
handles directly into h_free_list. But using two free lists makes
reuses occur later and in a less deterministic order. */

static void
allocate_more_handles(void)
{
if (h_free_list_2 >= 0) {
h_free_list = h_free_list_2;
h_free_list_2 = -1;
return;
}

Py_ssize_t base = (h_num_allocated < CONSTANT_H__TOTAL ?
CONSTANT_H__TOTAL : h_num_allocated);
Py_ssize_t i, allocate = (base / 2) * 3 + 32;
Expand All @@ -31,7 +42,8 @@ allocate_more_handles(void)
new_handles[CONSTANT_H_TRUE] = Py_True;
new_handles[CONSTANT_H_VALUEERROR] = PyExc_ValueError;
new_handles[CONSTANT_H_TYPEERROR] = PyExc_TypeError;
assert(CONSTANT_H__TOTAL == 6);
HPY_ASSERT(CONSTANT_H__TOTAL == 6,
("update handles.c with the list of constants"));
}

PyMem_Free(all_handles);
Expand Down Expand Up @@ -59,16 +71,39 @@ _py2h(PyObject *obj)
PyObject *
_h2py(HPy h)
{
HPY_ASSERT(h._i >= 0 && h._i < h_num_allocated,
("using an HPy containing garbage: _i = %zd", h._i));
// If HPy_IsNull(h), the h._i = 0 and the line below returns the
// pointer attached to the 0th handle, i.e. NULL.
return all_handles[h._i];
PyObject *result = all_handles[h._i];
if (h._i == 0) {
HPY_ASSERT(result == NULL, ("handle number 0 doesn't contain NULL"));
return NULL;
}
HPY_ASSERT((((Py_ssize_t)result) & 1) == 0,
("using an HPy that was freed already (or never allocated): _i = %zd",
h._i));
HPY_ASSERT(result != NULL,
("NULL PyObject unexpected in handle _i = %zd", h._i));
HPY_ASSERT(Py_REFCNT(result) > 0,
("bogus (freed?) PyObject found in handle _i = %zd", h._i));
return result;
}

void
_hclose(HPy h)
{
Py_ssize_t i = h._i;
Py_XDECREF(all_handles[i]);
all_handles[i] = (PyObject *)((h_free_list << 1) | 1);
h_free_list = i;
HPY_ASSERT(i >= 0 && i < h_num_allocated,
("freeing an HPy containing garbage: _i = %zd", i));
HPY_ASSERT(i != 0, ("freeing HPy_NULL is not allowed"));
PyObject *old = all_handles[i];
HPY_ASSERT((((Py_ssize_t)old) & 1) == 0,
("freeing an HPy that was freed already (or never allocated): _i = %zd",
i));
HPY_ASSERT(Py_REFCNT(old) > 0,
("bogus PyObject found while freeing handle _i = %zd", h._i));
all_handles[i] = (PyObject *)((h_free_list_2 << 1) | 1);
h_free_list_2 = i;
Py_DECREF(old);
}
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
'hpy/universal/src/ctx_module.c',
'hpy/universal/src/ctx_meth.c',
'hpy/universal/src/ctx_misc.c',
'hpy/universal/src/debugmode.c',
Copy link
Collaborator

Choose a reason for hiding this comment

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

In my idea, the "debug mode" be something different, i.e. a full wrapper around the ctx which does many extra checks, including potentially expensive ones, and will . So, maybe we should call this file differently?

'hpy/devel/src/runtime/ctx_type.c',
'hpy/devel/src/runtime/argparse.c',
],
Expand Down