Подтвердить что ты не робот

Обращение к санированию модулей Boost.Python

Мой проект включает большую библиотеку С++ и привязки Python (через Boost.Python). Набор тестов в основном написан поверх привязок Python, и я хотел бы запустить его с дезинфицирующими устройствами, начиная с ASAN.

Я запускаю macOS (10.13.1 FWIW, но у меня тоже была проблема с предыдущими версиями), и я не могу найти способ запустить ASAN на модулях Python (я очень сомневаюсь, что это связано с Boost.Python, я полагаю, это то же самое с другими методами).

Вот простой модуль Python:

// 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);
}

здесь используется Makefile, сделанный для 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 [email protected] $< $(LIBS)

check: all
        $(ENV) $(PYTHON) -c 'import hello_ext; print(hello_ext.greet())'

clean:
        -rm -f hello_ext.so

Без асана все работает хорошо (хорошо, слишком хорошо на самом деле...). Но с ASAN я нажал LD_PRELOAD как проблемы:

$ 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

Хорошо, пусть это сделает: define 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())'

Позвольте с подозрением относиться к SIP, поэтому я отключил SIP здесь и разрешил символические ссылки:

$ 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())'

Какой правильный способ сделать это? Я также пытался загрузить libasan с помощью ctypes.PyDLL, и даже с помощью sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) я не могу заставить это работать.

4b9b3361

Ответ 1

Итак, мне, наконец, удалось заставить это работать:

$ 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)
[...]

Что изменилось? Ничего в цепочке компиляции, просто вызов.

Пусть PYDIR=/opt/local/Library/Frameworks/Python.framework/Versions/3.5: ранее я вызывал $PYDIR/bin/python3.5 (потому что /opt/local/bin/python3.5 является символической ссылкой на него), теперь я вызываю $PYDIR/Resources/Python.app/Contents/MacOS/Python.

Чтобы понять, что происходит, я побежал DYLD_INSERT_LIBRARIES=$libasan python3.5 и искал его открытые файлы

$ 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

Очевидно, что libasan здесь нет, и что вся проблема. Однако я также заметил, что ps имел в виду другой Python, чем тот, который я запускал (и, конечно, это часть открытых файлов).

Оказалось, что в этом каталоге есть несколько исполняемых файлов Python: $PYDIR/bin/python3.5 и $PYDIR/Resources/Python.app/Contents/MacOS/Python, а первый, как и другой, отскакивает ко второму. Если я запустил второй с 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 есть! По-видимому, первый Python вызывает второй, а DYLD_INSERT_LIBRARIES не перенаправляется.

В настоящее время я понятия не имею, почему есть два Pythons. Это не похоже на MacPorts, так же как и на Apple Python.

$ 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

Ответ 2

Это может быть менее идеальный ответ, но он должен предоставить вам то, что вам нужно.

Я предлагаю вам создать проект Xcode для создания всего (да, я знаю, что вы хотите использовать make, который приходит позже)

Предполагая, что вы уже знаете, как создать проект Xcode, все, что я пропустил, чтобы включить Address Sanitizer:

ProductSchemeEdit Scheme откроет это окно: Изменить схему

Установите флажки для Address Sanitizer. Вы должны сделать это только для своего основного приложения. По моему опыту все зависимости будут построены соответствующим образом.

Далее Создайте основную цель приложения. Нам нужно будет изучить вызовы компилятора и компоновщика, чтобы мы могли скопировать все необходимые флаги/шаги в файлы make.

Build Output

Я обвел две соответствующие кнопки, чтобы получить выход. Самая правая кнопка будет расширять вызов компилятора, используемый для сборки.

соответствующий вывод

Этот снимок показывает как кнопку сохранения (это может быть проще рассмотреть в другой программе), так и некоторые соответствующие флаги, используемые для построения. Вам нужно будет изучить результат для всех целей (заговоров), чтобы получить четкое изображение.

Надеюсь, это поможет. FWIW проект в моем примере имеет настраиваемый модуль Python, написанный на С++ (напрямую с помощью libPython, а не Boost), поэтому я знаю, что вы можете использовать Asan для тех, которые даже используют поставляемые системой Python фреймворки.