0

I am following the SWIG tutorial and I'm currently on the section: "32.9.1 Converting Python list to a char **". The example in question returns a malloc error on my machine:

import example  
example.print_args(["a","bc","dc"])

python(57911,0x10bd32e00) malloc: *** error for object 0x7f7ee0406b90: pointer being freed was not allocated python(57911,0x10bd32e00) malloc: *** set a breakpoint in malloc_error_break to debug 1 57911 abort python 1 57911 abort python

The error is unexpected as this is exactly the code that the tutorial offers. Any help welcome! Thanks in advance

Specs:

  • MacOS Big Sur
  • Python 3.8
  • C++17

Here are my setup.py (the whole archive for reproducibility):

#!/usr/bin/env python

"""
setup.py file for SWIG example
"""

from distutils.core import setup, Extension
import os
import sys
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++'
#
example_module = Extension('_example',
                           srcFiles,  # + ['example.cpp'], # ['example_wrap.cxx', 'example.cpp'],
                           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"],
      )

1 Answer 1

2

The example code would work with Python 2, but has a bug as well as a syntax change for Python 3. char** must be passed byte strings, which are the default in Python 2 when using "string" syntax, but need a leading b, e.g. b"string" in Python 3.

This works:

import example  
example.print_args([b"a",b"bc",b"dc"])

The crash is due to a bug calling free twice if an incorrect parameter type is found. Make the following change to the example:

      if (PyString_Check(o)) {
        $1[i] = PyString_AsString(PyList_GetItem($input, i));
      } else {
        //free($1); // REMOVE THIS FREE
        PyErr_SetString(PyExc_TypeError, "list must contain strings");
        SWIG_fail;

SWIG_fail; ends up called the freearg typemap, which calls free a second time. With this change, you should see the following if passing incorrect arguments, such as a non-list or Unicode strings instead of byte strings:

>>> import argv
>>> argv.print_args(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\argv.py", line 66, in print_args
    return _argv.print_args(argv)
TypeError: not a list
>>> argv.print_args(['abc','def'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\argv.py", line 66, in print_args
    return _argv.print_args(argv)
TypeError: list must contain strings
>>> argv.print_args([b'abc',b'def'])
argv[0] = abc
argv[1] = def
2

Changing the error message to "list must contain byte strings" would help as well 😊

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

2 Comments

Thanks Mark. That fixed it. Do you mind if I use your reply to propose an update to the documentation? I think the SWIG maintainers would be happy with it.
@Guillaume Go ahead. There are probably lots of examples that have Python 2/3 differences, but the double-free bug is definitely something to fix.

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.