SWIG教程中Python列表转char**示例触发malloc错误求助
char** with SWIG on macOS Let's break down what's happening here and how to fix it:
First, that malloc error (pointer being freed was not allocated) almost always means there's a mismatch in memory management: your code is trying to free memory that wasn't allocated with malloc (or was already freed). In this case, it's likely the SWIG-generated code is attempting to release Python-managed string pointers instead of memory explicitly allocated for the C++ side.
Why This Happens
The default SWIG typemap for converting Python lists to char** might be directly passing pointers to Python's internal string storage (which Python manages) instead of creating copies of the strings in heap memory allocated via malloc. When SWIG tries to free those pointers later, it hits the error because that memory wasn't allocated by the C runtime.
Step-by-Step Fix
1. Update Your SWIG Interface File (example.i)
Replace your existing interface code with this, which explicitly handles memory allocation and cleanup correctly:
%module example %{ #include <stdlib.h> #include <string.h> #include <stdio.h> %} // Typemap to convert Python list to char** (with proper memory allocation) %typemap(in) char ** { if (!PyList_Check($input)) { PyErr_SetString(PyExc_TypeError, "Input must be a list of strings"); return NULL; } int list_size = PyList_Size($input); // Allocate array of char pointers (plus NULL terminator) $1 = (char**)malloc((list_size + 1) * sizeof(char*)); if (!$1) { PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for argument array"); return NULL; } for (int i = 0; i < list_size; i++) { PyObject* item = PyList_GetItem($input, i); if (!PyUnicode_Check(item)) { // Clean up already allocated memory on error for (int j = 0; j < i; j++) free($1[j]); free($1); PyErr_SetString(PyExc_TypeError, "All list items must be strings"); return NULL; } const char* py_str = PyUnicode_AsUTF8(item); // Allocate memory for the string copy $1[i] = (char*)malloc(strlen(py_str) + 1); if (!$1[i]) { // Cleanup on failure for (int j = 0; j < i; j++) free($1[j]); free($1); PyErr_SetString(PyExc_MemoryError, "Failed to allocate memory for string"); return NULL; } strcpy($1[i], py_str); } $1[list_size] = NULL; // Null-terminate the array for C-style handling } // Typemap to free the allocated char** after function call %typemap(freearg) char ** { if ($1) { for (int i = 0; $1[i]; i++) { free($1[i]); } free($1); } } // Your target function declaration %inline %{ void print_args(char** args) { for (int i = 0; args[i]; i++) { printf("Argument %d: %s\n", i, args[i]); } } %}
2. Clean Up Your setup.py
Fix the commented-out Extension configuration to ensure all source files are included properly:
#!/usr/bin/env python """ setup.py file for SWIG example """ from distutils.core import setup, Extension import os import glob # gather up all the source files srcFiles = ['example.i'] includeDirs = [] srcDir = os.path.abspath('src') for root, dirnames, filenames in os.walk(srcDir): for dirname in dirnames: absPath = os.path.join(root, dirname) globStr = "%s/*.c*" % absPath files = glob.glob(globStr) includeDirs.append(absPath) srcFiles += files extra_args = ['-stdlib=libc++', '-mmacosx-version-min=10.7', '-std=c++17', '-fno-rtti'] os.environ["CC"] = 'clang++' # Properly define the extension module example_module = Extension( '_example', srcFiles, include_dirs=includeDirs, swig_opts=['-c++'], extra_compile_args=extra_args, ) setup( name='example', version='0.1', author="SWIG Docs", description="""Simple swig example from docs""", ext_modules=[example_module], py_modules=["example"], )
3. Recompile and Test
Run these commands to rebuild the extension:
# Clean previous builds (optional but recommended) rm -rf build _example.so example.py example_wrap.cxx # Build the extension python setup.py build_ext --inplace
Now test again:
import example example.print_args(["a","bc","dc"])
This should work without the malloc error, as we're now explicitly copying each string into malloc-allocated memory, then properly freeing that memory after the function call.
内容的提问来源于stack exchange,提问作者Guillaume

