Reputation: 19
I've been learning about extending Python with C and I finally got it to work in some way, but I'm getting this really weird error. I made a test module with a single function to test if a number is prime. Here is the code:
cmodule.c
#include <stdbool.h>
#include <math.h>
#include <Python.h>
bool isprime(int n) {
if (n == 0 || n == 1)
return false;
for (int i = 2; i < (int)sqrt(n) + 1; i++) {
if (n % i == 0)
return false;
}
return true;
}
static PyObject * isprime_wrapper(PyObject * self, PyObject * args) {
int n;
if (!PyArg_ParseTuple(args, "i", &n))
return NULL;
bool retval = isprime(n);
if (retval)
return Py_True;
else
return Py_False;
}
static PyMethodDef methods[] = {
{"isprime", isprime_wrapper, METH_VARARGS, "Tests if a number is prime."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef cmodule = {
PyModuleDef_HEAD_INIT,
"cmodule",
"Test module.",
-1,
methods
};
PyMODINIT_FUNC PyInit_cmodule(void) {
return PyModule_Create(&cmodule);
}
setup.py
from distutils.core import setup, Extension
cmodule = Extension("cmodule", sources = ["cmodule.c"])
setup(name = "CModuleTest",
ext_modules = [cmodule])
At first glance it works fine. I run python3.6 setup.py build
and it builds with no errors, and I can go into the directory with the .so file, start up a Python session, and call cmodule.isprime() fine. However, the weird part is when I use the code in a loop, where I get this error:
>>> import cmodule
>>> for i in range(1, 1000001):
... n = cmodule.isprime(i)
...
*** Error in `python3.6': free(): invalid pointer: 0x0000561cc1faf620 ***
I can add the full backtrace if anyone would find it helpful. I printed out all the values of i while doing this, and it seemed to always be getting this error when it tries to run isprime(154). However, when I just open up Python in the terminal and try running isprime(154) or any other number by itself, it works fine. The only time I've been able to replicate this is in the loop, and I have no clue where it could be coming from. I've looked at other people that have had similar problems and it seemed to stem from them using free() in their C code improperly, but I never call free() from my code. Does anyone have an idea what could be causing this? Thanks for any help.
Upvotes: 0
Views: 1890
Reputation: 177685
CPython objects are referenced counted and returning Py_True and Py_False could be the issue. Use Py_RETURN_TRUE, etc. instead. They properly increment the reference count of and return their respective singleton objects.
Upvotes: 3