python c++ boost-python address-sanitizer

Dirección de desinfección de los módulos Boost.Python.



c++ boost-python (2)

Mi proyecto incluye una gran biblioteca de C ++ y enlaces Python (a través de Boost.Python). El conjunto de pruebas está escrito principalmente sobre los enlaces de Python, y me gustaría ejecutarlo con desinfectantes, comenzando con ASAN.

Estoy ejecutando macOS (10.13.1 FWIW, pero también tuve el problema con versiones anteriores), y parece que no puedo encontrar una manera de ejecutar ASAN en los módulos de Python (dudo mucho que esto esté relacionado con Boost.Python , Supongo que es lo mismo con otras técnicas).

Aquí hay un módulo de Python simple:

// hello_ext.cc #include <boost/python.hpp> char const* greet() { auto* res = new char[100]; std::strcpy(res, "Hello, world!"); delete [] res; return res; } BOOST_PYTHON_MODULE(hello_ext) { using namespace boost::python; def("greet", greet); }

Aquí está el Makefile que utilicé, hecho para MacPorts:

// Makefile CXX = clang++-mp-4.0 CXXFLAGS = -g -std=c++14 -fsanitize=address -fno-omit-frame-pointer CPPFLAGS = -isystem/opt/local/include $$($(PYTHON_CONFIG) --includes) LDFLAGS = -L/opt/local/lib PYTHON = python3.5 PYTHON_CONFIG = python3.5-config LIBS = -lboost_python3-mt $$($(PYTHON_CONFIG) --ldflags) all: hello_ext.so hello_ext.so: hello_ext.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $< $(LIBS) check: all $(ENV) $(PYTHON) -c ''import hello_ext; print(hello_ext.greet())'' clean: -rm -f hello_ext.so

Sin asan, todo funciona bien (bueno, demasiado bien en realidad ...). Pero con ASAN, golpeé LD_PRELOAD como problemas:

$ make check python -c ''import hello_ext; print(hello_ext.greet())'' ==19013==ERROR: Interceptors are not working. This may be because AddressSanitizer is loaded too late (e.g. via dlopen). Please launch the executable with: DYLD_INSERT_LIBRARIES=/opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib "interceptors not installed" && 0make: *** [check] Abort trap: 6

Bien, vamos a hacer eso: definir DYLD_INSERT_LIBRARIES

$ DYLD_INSERT_LIBRARIES=/opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib / python -c ''import hello_ext; print(hello_ext.greet())'' ==19023==ERROR: Interceptors are not working. This may be because AddressSanitizer is loaded too late (e.g. via dlopen). Please launch the executable with: DYLD_INSERT_LIBRARIES=/opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib "interceptors not installed" && 0zsh: abort DYLD_INSERT_LIBRARIES= python -c ''import hello_ext; print(hello_ext.greet())''

Sospechemos de SIP, así que deshabilité SIP aquí y resolvemos los enlaces simbólicos:

$ DYLD_INSERT_LIBRARIES=/opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib / /opt/local/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 -c ''import hello_ext; print(hello_ext.greet())'' ==19026==ERROR: Interceptors are not working. This may be because AddressSanitizer is loaded too late (e.g. via dlopen). Please launch the executable with: DYLD_INSERT_LIBRARIES=/opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib "interceptors not installed" && 0zsh: abort DYLD_INSERT_LIBRARIES= -c ''import hello_ext; print(hello_ext.greet())''

¿Cuál es la manera correcta de hacer eso? También he intentado cargar libasan con ctypes.PyDLL , e incluso con sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) No puedo hacer que esto funcione.


Entonces, finalmente logré que esto funcionara:

$ libasan=/opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib $ python=/opt/local/Library/Frameworks/Python.framework/Versions/3.5/Resources/Python.app/Contents/MacOS/Python $ DYLD_INSERT_LIBRARIES=$libasan $python -c ''import hello_ext; print(hello_ext.greet())'' ================================================================= ==70859==ERROR: AddressSanitizer: heap-use-after-free on address 0x60b000002770 at pc 0x000108c2ef60 bp 0x7ffee6fe8c20 sp 0x7ffee6fe83c8 READ of size 2 at 0x60b000002770 thread T0 #0 0x108c2ef5f in wrap_strlen (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x14f5f) #1 0x109a8d939 in PyUnicode_FromString (Python:x86_64+0x58939) [...]

¿Qué cambió? Nada en la cadena de compilación, solo la invocación.

Deje que PYDIR=/opt/local/Library/Frameworks/Python.framework/Versions/3.5 : anteriormente estaba llamando a $PYDIR/bin/python3.5 (porque /opt/local/bin/python3.5 es un enlace simbólico) , ahora llamo $PYDIR/Resources/Python.app/Contents/MacOS/Python .

Para entender lo que estaba pasando, ejecuté DYLD_INSERT_LIBRARIES=$libasan python3.5 , y busqué sus archivos abiertos

$ ps PID TTY TIME CMD 900 ttys000 0:07.96 -zsh 70897 ttys000 0:00.11 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/Resources/Python.app/Contents/MacOS/Python 53528 ttys001 0:05.14 -zsh 920 ttys002 0:10.28 -zsh $ lsof -p 70897 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME Python 70897 akim cwd DIR 1,4 480 8605949500 /Users/akim/src/lrde/vcsn/experiment/sanitizer Python 70897 akim txt REG 1,4 12988 8591019542 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/Resources/Python.app/Contents/MacOS/Python Python 70897 akim txt REG 1,4 2643240 8591012758 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/Python Python 70897 akim txt REG 1,4 107524 8590943656 /opt/local/lib/libintl.8.dylib Python 70897 akim txt REG 1,4 2097528 8590888556 /opt/local/lib/libiconv.2.dylib Python 70897 akim txt REG 1,4 20224 8591016920 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_heapq.cpython-35m-darwin.so Python 70897 akim txt REG 1,4 326996 8591375651 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/readline/gnureadline.cpython-35m-darwin.so Python 70897 akim txt REG 1,4 603008 8605907803 /opt/local/lib/libncurses.6.dylib Python 70897 akim txt REG 1,4 837248 8606849556 /usr/lib/dyld Python 70897 akim txt REG 1,4 1155837952 8606860187 /private/var/db/dyld/dyld_shared_cache_x86_64h Python 70897 akim 0u CHR 16,0 0t2756038 667 /dev/ttys000 Python 70897 akim 1u CHR 16,0 0t2756038 667 /dev/ttys000 Python 70897 akim 2u CHR 16,0 0t2756038 667 /dev/ttys000

Obviamente, libasan no está aquí, y ese es todo el problema. Sin embargo, también noté que ps se refería a otro Python distinto del que ejecuté (y, por supuesto, es parte de los archivos abiertos).

Resulta que hay varios ejecutables de Python en este directorio: $PYDIR/bin/python3.5 y $PYDIR/Resources/Python.app/Contents/MacOS/Python , y el primero, a la manera del otro, rebota a la segunda. Si ejecuto el segundo con DYLD_INSERT_LIBRARIES=$libasan

$ lsof -p 71114 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME Python 71114 akim cwd DIR 1,4 480 8605949500 /Users/akim/src/lrde/vcsn/experiment/sanitizer Python 71114 akim txt REG 1,4 12988 8591019542 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/Resources/Python.app/Contents/MacOS/Python Python 71114 akim txt REG 1,4 3013168 8604479549 /opt/local/libexec/llvm-4.0/lib/clang/4.0.1/lib/darwin/libclang_rt.asan_osx_dynamic.dylib Python 71114 akim txt REG 1,4 2643240 8591012758 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/Python Python 71114 akim txt REG 1,4 107524 8590943656 /opt/local/lib/libintl.8.dylib Python 71114 akim txt REG 1,4 2097528 8590888556 /opt/local/lib/libiconv.2.dylib Python 71114 akim txt REG 1,4 20224 8591016920 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_heapq.cpython-35m-darwin.so Python 71114 akim txt REG 1,4 326996 8591375651 /opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/readline/gnureadline.cpython-35m-darwin.so Python 71114 akim txt REG 1,4 603008 8605907803 /opt/local/lib/libncurses.6.dylib Python 71114 akim txt REG 1,4 837248 8606849556 /usr/lib/dyld Python 71114 akim 0u CHR 16,0 0t2781894 667 /dev/ttys000 Python 71114 akim 1u CHR 16,0 0t2781894 667 /dev/ttys000 Python 71114 akim 2u CHR 16,0 0t2781894 667 /dev/ttys000

/ o / libasan está ahí! Aparentemente, el primer Python llama al segundo, y DYLD_INSERT_LIBRARIES no se reenvía.

Actualmente no tengo idea de por qué hay dos pitones. No parece ser específico de MacPorts, ya que también es el caso de Python de Apple.

$ cd /System/Library/Frameworks/Python.framework/Versions/2.7 $ ls -l bin/python* lrwxr-xr-x 1 root wheel 7 10 déc 08:17 bin/python -> python2 lrwxr-xr-x 1 root wheel 14 10 déc 08:17 bin/python-config -> python2-config lrwxr-xr-x 1 root wheel 9 10 déc 08:17 bin/python2 -> python2.7 lrwxr-xr-x 1 root wheel 16 10 déc 08:17 bin/python2-config -> python2.7-config -rwxr-xr-x 1 root wheel 43104 1 déc 21:42 bin/python2.7 -rwxr-xr-x 1 root wheel 1818 16 jul 02:20 bin/python2.7-config lrwxr-xr-x 1 root wheel 8 10 déc 08:17 bin/pythonw -> pythonw2 lrwxr-xr-x 1 root wheel 10 10 déc 08:17 bin/pythonw2 -> pythonw2.7 -rwxr-xr-x 1 root wheel 43104 1 déc 21:42 bin/pythonw2.7 $ ls -l Resources/Python.app/Contents/MacOS/Python -rwxr-xr-x 1 root wheel 51744 1 déc 21:48 Resources/Python.app/Contents/MacOS/Python


Esta puede ser una respuesta menos que ideal, pero debería proporcionarle lo que necesita.

Te estoy proponiendo que hagas un proyecto Xcode para construir todo (sí, sé que quieres usar make, eso viene más adelante)

Suponiendo que usted ya sabe cómo obtener un proyecto de Xcode construyendo todo lo que haré para habilitar Address Sanitizer:

Product -> Scheme -> Edit Scheme abrirá esta ventana:

Marque las casillas de Desinfectante de direcciones. Solo debes hacer esto para tu aplicación principal. En mi experiencia, todas las dependencias serán construidas apropiadamente.

Siguiente Construye el objetivo principal de la aplicación. Tendremos que examinar las invocaciones del compilador y del enlazador para poder copiar los indicadores / pasos necesarios en los archivos make.

He circulado los 2 botones relevantes para obtener la salida. El botón de la derecha expandirá la invocación del compilador utilizada para construir.

Esta imagen muestra tanto un botón de guardar (que puede ser más fácil de examinar en otro programa) y algunas de las banderas relevantes utilizadas para la construcción. Deberá examinar la salida de todos los objetivos (dependencias) para obtener una imagen clara.

Espero que esto ayude. FWIW el proyecto en mi ejemplo tiene un módulo Python personalizado escrito en C ++ (directamente usando libPython, no Boost), así que sé que puede usar Asan en aquellos que usan los marcos Python provistos por el Sistema.