0

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.

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Worked perfectly! I never knew about those statements, thanks a ton!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.