Are executables produced with Cython really free of the source code?

The code is found in the original pyx-file next to your exe. Delete/don’t distribute this pyx-file with your exe.


When you look at the generated C-code, you will see why the error message is shown by your executable:

For a raised error, Cython will emit a code similar to the following:

__PYX_ERR(0, 11, __pyx_L3_error) 

where __PYX_ERR is a macro defined as:

#define __PYX_ERR(f_index, lineno, Ln_error) \
{ \
  __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \
}

and the variable __pyx_f is defined as

static const char *__pyx_f[] = {
  "test.pyx",
  "stringsource",
};

Basically __pyx_f[0] tells where the original code could be found. Now, when an exception is raised, the (embedded) Python interpreter looks for your original pyx-file and finds the corresponding code (this can be looked up in __Pyx_AddTraceback which is called when an error is raised).

Once this pyx-file is not around, the original source code will no longer be known to the Python interpreter/anybody else. However, the error trace will still show the names of the functions and line-numbers but no longer any code snippets.

The resulting executable (or extension if one creates one) doesn’t content any bytecode (as in pyc-files) and cannot be decompiled with tools like uncompyle: bytecode is produced when py-file is translated into Python-opcodes which are then evaluated in a huge loop in ceval.c. Yet for builtin/cython modules no bytecode is needed because the resulting code uses directly Python’s C-API, cutting out the need to have/evaluate the opcodes – these modules skip interpretation, which a reason for them being faster. Thus no bytecode will be in the executable.

One important note though: One should check that the linker doesn’t include debug information (and thus the C-code where the pyx-file content can be found as comments). MSVC with /Z7 options is such an example.


However, the resulting executable can be disassembled to assembler and then the generated C-code can be reverse engineered – so while cythonizing is Ok to make it hard to understand the code, it is not the right tool to conceal keys or security algorithms.

Leave a Comment