Извинения за длинную должность;Я снова вернулся к аналогичной проблеме с отладкой - в случае, когда вы отправляетесь в долгий путь к отладчику, чтобы окончательно выявить, что в действительности нет ошибки - поэтому я просто хотел бы опубликовать свои заметки и некоторый код здесь (явсе еще на Python 2.7, Ubuntu 11.04).Что касается вопроса OP - в более новых gdb
, его также можно разбить, используя функцию id(...)
в скрипте Python и имея gdb
break на builtin_id
;но вот более подробно:
Опять же, у меня была проблема с модулем разделяемой библиотеки C .so для Python;на этот раз это был svn.client
, который является модулем Swig (см. также здесь );в Debian / Ubuntu доступно через sudo apt-get install python-subversion
( filelist ).Проблема возникла при попытке запустить Пример 8.3.Искатель состояния Python - Использование API (svnbook) Этот пример должен делать то же, что и команда терминала svn status
;но когда я попробовал его на одной из моих рабочих копий, он вылетел с сообщением « Ошибка (22): Ошибка преобразования записи в каталоге« путь »в UTF-8 », даже если svn status
обрабатывалтот же каталог рабочих копий (WC) (вот уже много лет), поэтому я хотел посмотреть, откуда это взялось.Моя версия тестового скрипта python-subversion-test.py ;и мой полный журнал отладки находится в logsvnpy.gz (сжатый текстовый файл, ~ 188K без сжатия, если кто-то захочет пройти через бесконечные шаги и обратные пути) - это сокращенная версия.У меня установлены оба Python 2.7 и 3.2, но 2.7 по умолчанию установлены в Ubuntu 11.04:
$ ls -la $(which python python-dbg)
lrwxrwxrwx 1 root root 9 2012-02-29 07:31 /usr/bin/python -> python2.7
lrwxrwxrwx 1 root root 13 2013-04-07 03:01 /usr/bin/python-dbg -> python2.7-dbg
$ apt-show-versions -r 'python[^-]+'
libpython2.7/natty uptodate 2.7.1-5ubuntu2.2
libpython3.2/natty uptodate 3.2-1ubuntu1.2
python2.7/natty uptodate 2.7.1-5ubuntu2.2
python2.7-dbg/natty uptodate 2.7.1-5ubuntu2.2
python2.7-dev/natty uptodate 2.7.1-5ubuntu2.2
python2.7-minimal/natty uptodate 2.7.1-5ubuntu2.2
python3/natty uptodate 3.2-1ubuntu1
python3-minimal/natty uptodate 3.2-1ubuntu1
python3.2/natty uptodate 3.2-1ubuntu1.2
python3.2-minimal/natty uptodate 3.2-1ubuntu1.2
Первое, на что нужно обратить внимание, - это как работает пример Python: там, чтобы получить статус всех файлов вкаталог, сначала вызывается svn.client.svn_client_status2
- кроме пути, также с _status_callback
в аргументах, в качестве функции обратного вызова в Python для регистрации - и затем блоки.Пока status2
блокируется, базовый модуль выполняет итерацию по всем файлам в пути к каталогу WC;и для каждой записи файла он вызывает зарегистрированный _status_callback
, который должен распечатать информацию о записи.По окончании этой рекурсии status2
завершается.Таким образом, сбой UTF-8 должен исходить из базового модуля.Дальнейшая проверка этого модуля:
$ python -c 'import inspect,pprint,svn.client; pprint.pprint(inspect.getmembers(svn.client))' | grep status
('status', <function svn_client_status at 0xb7351f44>),
('status2', <function svn_client_status2 at 0xb7351f0c>),
('status3', <function svn_client_status3 at 0xb7351ed4>),
('status4', <function svn_client_status4 at 0xb7351e9c>),
('svn_client_status', <function svn_client_status at 0xb7351f44>),
# ...
... показывает, что существуют другие функции statusX
- однако, status3
завершился ошибкой с той же ошибкой UTF-8;в то время как status4
вызвал ошибку сегментации (которая становится еще одной проблемой для отладки).
И снова, как в моем комментарии к ответу @ EliBendersky , я хотел создать точку остановав Python, чтобы впоследствии получить какой-то стек вызовов функций C, который бы показал, где возникает проблема - без необходимости перестраивать модули C из исходного кода;но это оказалось не так просто.
Python и gdb
Прежде всего, одна вещь, которая может быть очень запутанной, это отношения между gdb
и Python;Типичные ресурсы, появляющиеся здесь:
- http://wiki.python.org/moin/DebuggingWithGdb - упоминает
gdbinit
в "GDB Macros", That release27-maint / Misc / gdbinit находится в исходном дереве Python;определяет команды gdb
, такие как pylocals
и pyframe
, но также упоминает:
# ПРИМЕЧАНИЕ. Если у вас есть gdb 7 или более поздняя версия, он напрямую поддерживает отладку Python
# со встроенныммакросы, которые вы можете найти лучше, чем здесь.
# См. Tools / gdb / libpython.py и http://bugs.python.org/issue8032.
Возможности/ EasierPythonDebugging - FedoraProject - содержит пример, упоминает пакет Fedora python-debuginfo
и libpython
- Tools / gdb / libpython.py также на Pythonисходное дерево, и в нем упоминается:
Начиная с GDB 7, можно настроить сборку GDB --with-python, позволяя расширять GDB
с помощью кода Python, например, для визуализации данных библиотеки
например, для типов C ++ STL.....
Этот модуль включает знания о деталях реализации libpython, поэтому
что мы можем испускать полезные визуализации, например строка, список, диктат, рамка
предоставление информации о файле / строке и состоянии локальных переменных
- cpython / Lib / test / test_gdb.py - судя по всему из cpython, похоже, тестирует функциональность
gdb
из Python
Это немного сбивает с толку - кроме указателя, лучше получить себя gdb
v.7; Мне удалось получить для моей ОС:
$ apt-show-versions gdb
gdb 7.3-50.20110806-cvs newer than version in archive
Быстрый способ проверить, поддерживает ли gdb
Python:
$ gdb --batch --eval-command="python print gdb"
<module 'gdb' (built-in)>
$ python -c 'import gdb; print gdb'
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: No module named gdb
... но gdb
, поддерживающий Python, не означает, что Python сам по себе может получить доступ к функциональности gdb
(очевидно, gdb
имеет свой собственный встроенный отдельный интерпретатор Python).
Оказывается, в Ubuntu 11.04 пакет python2.7-dbg
устанавливает файл libpython2.7.so.1.0-gdb.py
:
$ find / -xdev -name '*libpython*' 2>/dev/null | grep '\.py'
/usr/lib/debug/usr/lib/libpython2.7.so.1.0-gdb.py
$ sudo ln -s /usr/lib/debug/usr/lib/libpython2.7.so.1.0-gdb.py /usr/lib/debug/usr/lib/libpython.py
... и это тот, который соответствует упомянутому Tools/gdb/libpython.py
; символическая ссылка позволит нам ссылаться на него как libpython
и использовать скрипт импорта, упомянутый в Features / EasierPythonDebugging .
Сценарий test_gdb.py
на самом деле предназначен для Python 3 - я изменил его для 2.7 и разместил в test_gdb2.7.py . Этот скрипт вызывает gdb
через системный вызов ОС и проверяет его функциональность Python с выводом на stdout; он также принимает параметр командной строки -imp-lp
, который будет import libpython
в gdb
перед выполнением других команд. Так, например:
$ python-dbg test_gdb2.7.py
...
*** test_prettyprint ***
42 (self=0x0, v=0x8333fc8)
[] (self=0x0, v=0xb7f7506c)
('foo', 'bar', 'baz') (self=0x0, v=0xb7f7d234)
[0, 1, 2, 3, 4] (self=0x0, v=0xb7f7506c)
...
$ python-dbg test_gdb2.7.py -imp-lp
...
*** test_prettyprint ***
42 (self=0x0, v=42)
[] (self=0x0, v=[])
('foo', 'bar', 'baz') (self=0x0, v=('foo', 'bar', 'baz'))
[0, 1, 2, 3, 4] (self=0x0, v=[0, 1, 2, 3, 4])
...
Таким образом, libpython.py
предназначен специально для интерпретатора Python внутри gdb
и помогает gdb
печатать представления Python (v=[]
) вместо просто адресов памяти (v=0xb7f7506c
) - что только полезно, если gdb
происходит для отладки скрипта Python (точнее, он отлаживает исполняемый файл Python, который интерпретирует скрипт).
Сценарий test_gdb.py
также дает указатель, что вы можете " ... запустить" python -c'id (DATA) '"под gdb с точкой останова на builtin_id
"; для проверки этого я опубликовал bash-скрипт gdb_py_so_test.sh , который создает исполняемый файл с функцией подсчета потоков, а также обычные модули distutils и swig (в обеих версиях отладки и выпуска), которые взаимодействуют с та же функция. Он также создает .gdbinit
с точками останова класса Python как gdb
, так и gdb
- и, наконец, он запускает gdb
на Python (загрузка одного из общих модулей), где пользователь может надеяться увидеть, являются ли точки останова действительно срабатывает.
segfault в gdb без восстановления исходного кода
Сначала я сосредоточился на сегментарной ошибке status4
и хотел точно знать, из какого модуля поступает эта функция. Я использовал функцию, которую можно найти в debug_funcs.py ; который может вызываться с отдельным регулярным выражением для функций и модулей и может генерировать что-то вроде:
$ python python-subversion-test.py ./MyRepoWCDir
# ...
# example for debug_funcs.showLoadedModules(r'(?=.*\.(so|pyc))(?=.*svn)(?=.*client)')
#
svn.client 0xb74b83d4L <module 'svn.client' from '/usr/lib/pymodules/python2.7/svn/client.pyc'>
_client 0xb7415614L <module '_client' from '/usr/lib/pymodules/python2.7/libsvn/_client.so'>
libsvn.client 0xb74155b4L <module 'libsvn.client' from '/usr/lib/pymodules/python2.7/libsvn/client.pyc'>
#
# example for debug_funcs.showFunctionsInLoadedModules(r'status4', r'(?=.*\.(so|pyc))(?=.*svn)')
#
0xb738c4fcL libsvn.client svn_client_status4 libsvn/client.pyc
0xb74e9eecL _client svn_client_status4 libsvn/_client.so
0xb738c4fcL svn.client status4 svn/client.pyc
0xb738c4fcL svn.client svn_client_status4 svn/client.pyc
Однако учтите, что:
$ python-dbg python-subversion-test.py ./MyRepoWCDir
# ...
0x90fc574 - _client /usr/lib/pymodules/python2.7/libsvn/_client_d.so
# ...
0x912b30c _client svn_client_status4 libsvn/_client_d.so
# ...
$ apt-show-versions -r python-subversion
python-subversion/natty uptodate 1.6.12dfsg-4ubuntu2.1
python-subversion-dbg/natty uptodate 1.6.12dfsg-4ubuntu2.1
... python-dbg
загрузит различные (отладочные, _d
) версии .so
модулей libsvn
(или python-subversion
); и это потому, что у меня установлен пакет python-subversion-dbg
.
В любом случае нам может показаться, что мы знаем адреса, по которым модули и соответствующие функции загружаются при каждом вызове скрипта Python - что позволило бы нам разместить точку останова gdb
по адресу программы ; учитывая, что здесь мы работаем с "vanilla" .so (которые не были восстановлены из исходного кода). Однако Python сам по себе не видит, что _client.so
фактически использует libsvn_client-1.so
:
$ ls -la $(locate '*2.7*/_client*.so') #check locations
$ ls -la $(locate 'libsvn_client') #check locations
$ ldd /usr/lib/pyshared/python2.7/libsvn/_client.so | grep client
libsvn_client-1.so.1 => /usr/lib/libsvn_client-1.so.1 (0x0037f000)
#
# instead of nm, also can use:
# objdump -dSlr file | grep '^[[:digit:]].*status4' | grep -v '^$\|^[[:space:]]'
#
$ nm -D /usr/lib/pyshared/python2.7/libsvn/_client.so | grep status4
U svn_client_status4
$ nm -a /usr/lib/pyshared/python2.7/libsvn/_client_d.so | grep status4
00029a50 t _wrap_svn_client_status4
U svn_client_status4
$ nm -D /usr/lib/libsvn_client-1.so.1 | grep status4 # -a: no symbols
00038c10 T svn_client_status4
Из Python мы можем сделать системный вызов, запросить /proc/pid/maps
для адреса, куда загружен libsvn_client-1.so
, и добавить к нему адрес, сообщенный последней командой nm -D
для смещения svn_client_status4
; и получить адрес, по которому мы можем взломать gdb
(с синтаксисом b *0xAddress
) - но это не обязательно, потому что если nm
может видеть символ, то и gdb
- так что мы можем разбить непосредственно на имя функции Другое дело, что в случае segfault, gdb
останавливается сам по себе, и мы можем выдать обратную трассировку (примечание: используйте Ctrl-X A для выхода из режима TUI gdb после layout asm
):
$ gdb --args python python-subversion-test.py ./AudioFPGA/
(gdb) r
Starting program: /usr/bin/python python-subversion-test.py ./MyRepoWCDir
...
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb) bt
#0 0x00000000 in ?? ()
#1 0x005a5bf3 in ?? () from /usr/lib/libsvn_client-1.so.1
#2 0x005dbf4a in ?? () from /usr/lib/libsvn_wc-1.so.1
#3 0x005dcea3 in ?? () from /usr/lib/libsvn_wc-1.so.1
#4 0x005dd240 in ?? () from /usr/lib/libsvn_wc-1.so.1
#5 0x005a5fe5 in svn_client_status4 () from /usr/lib/libsvn_client-1.so.1
#6 0x00d54dae in ?? () from /usr/lib/pymodules/python2.7/libsvn/_client.so
#7 0x080e0155 in PyEval_EvalFrameEx ()
...
(gdb) frame 1
#1 0x005a5bf3 in ?? () from /usr/lib/libsvn_client-1.so.1
(gdb) list
No symbol table is loaded. Use the "file" command.
(gdb) disas
No function contains program counter for selected frame.
(gdb) x/10i 0x005a5bf3
=> 0x5a5bf3: mov -0xc(%ebp),%ebx
0x5a5bf6: mov -0x8(%ebp),%esi
0x5a5bf9: mov -0x4(%ebp),%edi
0x5a5bfc: mov %ebp,%esp
(gdb) layout asm # No function contains program counter for selected frame (cannot show 0x5a5bf3)
(gdb) p svn_client_status4
$1 = {<text variable, no debug info>} 0x5a5c10 <svn_client_status4>
(gdb) frame 5
#5 0x005a5fe5 in svn_client_status4 () from /usr/lib/libsvn_client-1.so.1
(gdb) list
No symbol table is loaded. Use the "file" command.
(gdb) layout asm
│0x5a5fd8 <svn_client_status4+968> mov %esi,0x4(%esp) |
│0x5a5fdc <svn_client_status4+972> mov %eax,(%esp) |
│0x5a5fdf <svn_client_status4+975> mov -0x28(%ebp),%eax |
│0x5a5fe2 <svn_client_status4+978> call *0x38(%eax) |
>│0x5a5fe5 <svn_client_status4+981> test %eax,%eax |
│0x5a5fe7 <svn_client_status4+983> jne 0x5a5ce3 <svn_client_status4+211> |
│0x5a5fed <svn_client_status4+989> jmp 0x5a5ee3 <svn_client_status4+723> |
│0x5a5ff2 <svn_client_status4+994> lea -0x1fac(%ebx),%eax |
│0x5a5ff8 <svn_client_status4+1000> mov %eax,(%esp) |
Итак, наша ошибка происходит где-то в libsvn_client-1.so
, но в области памяти до svn_client_status4
запуска функции;и так как у нас нет отладочных символов - мы не можем сказать ничего другого, кроме этого.Использование python-dbg
может дать несколько иные результаты:
Program received signal SIGSEGV, Segmentation fault.
0x005aebf0 in ?? () from /usr/lib/libsvn_client-1.so.1
(gdb) bt
#0 0x005aebf0 in ?? () from /usr/lib/libsvn_client-1.so.1
#1 0x005e4f4a in ?? () from /usr/lib/libsvn_wc-1.so.1
#2 0x005e5ea3 in ?? () from /usr/lib/libsvn_wc-1.so.1
#3 0x005e6240 in ?? () from /usr/lib/libsvn_wc-1.so.1
#4 0x005aefe5 in svn_client_status4 () from /usr/lib/libsvn_client-1.so.1
#5 0x00d61e9e in _wrap_svn_client_status4 (self=0x0, args=0x8471214)
at /build/buildd/subversion-1.6.12dfsg/subversion/bindings/swig/python/svn_client.c:10001
...
(gdb) frame 4
#4 0x005aefe5 in svn_client_status4 () from /usr/lib/libsvn_client-1.so.1
(gdb) list
9876 in /build/buildd/subversion-1.6.12dfsg/subversion/bindings/swig/python/svn_client.c
(gdb) p svn_client_status4
$1 = {<text variable, no debug info>} 0x5aec10 <svn_client_status4>
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
...
0x00497a20 0x004c8be8 Yes /usr/lib/pymodules/python2.7/libsvn/_core_d.so
0x004e9fe0 0x004f52c8 Yes /usr/lib/libsvn_swig_py2.7_d-1.so.1
0x004f9750 0x00501678 Yes (*) /usr/lib/libsvn_diff-1.so.1
0x0050f3e0 0x00539d08 Yes (*) /usr/lib/libsvn_subr-1.so.1
0x00552200 0x00572658 Yes (*) /usr/lib/libapr-1.so.0
0x0057ddb0 0x005b14b8 Yes (*) /usr/lib/libsvn_client-1.so.1
...
0x00c2a8f0 0x00d11cc8 Yes (*) /usr/lib/libxml2.so.2
0x00d3f860 0x00d6dc08 Yes /usr/lib/pymodules/python2.7/libsvn/_client_d.so
...
(*): Shared library is missing debugging information.
... но команда list
по-прежнему дает нам строку исходного текста, принадлежащую кадру 5 (не кадру 4), а мы по-прежнему этого не делаемузнать больше о svn_client_status4
: хотя модули python-subversion
загружены в своих версиях отладки, информация об отладке отсутствует для libsvn_client-1.so
.Итак, время перестраивать из исходного кода.
segfault в gdb с перестройкой исходного кода
Это реальный subversion
, который нам нужно перестроить, или, скорее, это часть библиотеки - так как у нас уже есть отладкамодули от python-subversion
;пакет в моей системе называется libsvn1
:
$ apt-show-versions -r 'libsvn'
libsvn1/natty uptodate 1.6.12dfsg-4ubuntu2.1
$ apt-cache search 'libsvn' | grep 'dbg'
python-subversion-dbg - Python bindings for Subversion (debug extension)
... и для него нет пакета отладки.Чтобы восстановить из исходного кода, я прошел через apt-get source libsvn1
, с зависимостями, найденными вручную через apt-rdepends --build-depends --follow=DEPENDS subversion
.В полном журнале есть больше подробностей - но здесь мы можем заметить, что пакет с исходным кодом может создавать как привязки SWIG Python (то есть python-subversion
), так и библиотеку Subversion (libsvn1
).Кроме того, я запустил make install
с расположением вне основного дерева ядра;это означает, что нужно было явно указать модули, собранные из источника, через переменные среды LD:
$ ELD=/path/to/src/subversion-1.6.12dfsg/tmpinst/usr/local/lib
$ LD_LIBRARY_PATH=$ELD:$ELD/svn-python/libsvn LD_PRELOAD="$ELD/libsvn_client-1.so $ELD/svn-python/libsvn/_core.so" gdb --args python python-subversion-test.py ./MyRepoWCDir
Одна хитрость здесь заключается в том, что для построения отладочных модулей SWIG требуется вызов с python-dbg
;очевидно, просто делать ./configure --enable-debug
не делает этого;и так, только _core.so
и т. д., хотя и с отладочной информацией.Если затем мы попытаемся принудительно установить его загрузку, как в приведенной выше команде, но с python-dbg
, мы получим undefined symbol: Py_InitModule4
, потому что:
$ objdump -d $(which python) | grep '^\w.*InitMod'
0813b770 <Py_InitModule4>:
$ objdump -d $(which python-dbg) | grep '^\w.*InitMod'
08124740 <Py_InitModule4TraceRefs>:
... python-dbg
имеет другой Py_InitModule4
функция.Это, однако, не было проблемой, потому что использовался просто python
(как в приведенном выше вызове), и gdb
все еще позволяло проходить через соответствующие функции во вновь построенном libsvn
(упомянутый скрипт Bash * 1235).* gdb_py_so_test.sh , в качестве примера строит базовый модуль Swig в версиях отладки и выпуска для подтверждения правильности процедуры).
С символами отладки для libsvn
стек вызова функции выглядит следующим образом(вставлено немного по-другому):
#5 0x0016e654 in svn_client_status4 (..., libsvn_client/status.c:369
#4 0x007fd209 in close_edit (..., libsvn_wc/status.c:2144
#3 0x007fafaa in get_dir_status (..., libsvn_wc/status.c:1033
#2 0x007fa4e7 in send_unversioned_item (..., libsvn_wc/status.c:722
#1 0x0016dd17 in tweak_status (..., libsvn_client/status.c:81
#0 0x00000000 in ?? ()
... и поскольку те же библиотечные функции также используются в командной строке svn client
, мы можем сравнить, скажем, кадр 5:
# `svn status`:
(gdb) p *(sb->real_status_func)
$3 = {svn_error_t *(void *, const char *, svn_wc_status2_t *, apr_pool_t *)} 0x805e199 <print_status>
...
# `python python-subversion-test.py`
(gdb) p *(svn_wc_status_func3_t*)sb->real_status_func
Cannot access memory at address 0x0
Таким образом, в случае вызова Python status4
, sb->real_status_func
имеет значение NULL, вызывая ошибку сегмента.Причину этого можно выяснить, как только мы начнем читать источник: в ./subversion/libsvn_client/deprecated.c
определение для status3
имеет:
svn_client_status3(svn_revnum_t *result_rev,
const char *path,
const svn_opt_revision_t *revision,
svn_wc_status_func2_t status_func,
void *status_baton,
....
struct status3_wrapper_baton swb = { 0 };
swb.old_func = status_func;
swb.old_baton = status_baton;
return svn_client_status4(result_rev, path, revision, status3_wrapper_func,
&swb, depth, get_all, update, no_ignore,
ignore_externals, changelists, ctx, pool);
... то есть, когда status3
вызывается сФункция обратного вызова создает структуру и назначает функцию одному из свойств структуры, а затем использует структуру при дальнейшем вызове status4
!Поскольку status3
на самом деле работает из Python - вывод заключается в том, что мы не можем правильно вызвать status4
из Python (поскольку это потребует создания структуры C в Python);и это в любом случае не имеет значения, потому что мы можем вызвать status3
из Python - который сам тогда вызывает status4
!
Тогда почему status4
адресуем из Python?Вероятно, потому что swig
просто автоматически сгенерировал интерфейс для него ... В любом случае, вот пример, где поездка в отладчик выявляет источник проблемы - но на самом деле не ошибка :)
Решение?Не используйте ошибку status4
.
C в модуле Python, в gdb с восстановлением исходного кода
Возвращаясь к ошибке UTF-8, которая произошла с status2
и status3
- это было проще, учитывая, что теперь доступны исходные версии модулей.Проблема была очевидна в функции entry_name_to_utf8
, и, изучив ее аргумент name
, можно было сначала понять, что имя файла, вызвавшего проблему, действительно содержало не ascii - но все еще допустимые символы UTF-8 (см. * 1274).* Программа для проверки / поиска символов UTF-8 / Unicode в строке в командной строке? - Суперпользователь ).Затем я использовал этот .gdbinit , чтобы создать точку останова класса Python для gdb, которая выводила бы имена файлов и ломалась только при совпадении с проблемным.
Тогда возникает вопрос - почему клиент командной строки svn status
не падает на том же имени файла? Пройдя по svn status
и python python-subversion-test.py
, можно сравнить соответствующие стеки вызовов функций:
# call stack Python module:
#
_wrap_svn_client_status3 subversion/bindings/swig/python/svn_client.c * allocs:
(svn_swig_py_get_pool_arg(args, SWIGTYPE_p_apr_pool_t, &_global_py_pool, &_global_pool))
svn_client_status3 subversion/libsvn_client/deprecated.c
svn_client_status4 subversion/libsvn_client/status.c
close_edit subversion/libsvn_wc/status.c
get_dir_status subversion/libsvn_wc/status.c
# call stack svn client:
#
main subversion/svn/main.c
svn_cl__status subversion/svn/status-cmd.c * allocs
(subpool = svn_pool_create(pool))
svn_client_status4 subversion/libsvn_client/status.c
close_edit subversion/libsvn_delta/cancel.c
close_edit subversion/libsvn_wc/status.c
get_dir_status subversion/libsvn_wc/status.c
# svn call stack:
# ... svn_client_status4 - starts pool
#
get_dir_status subversion/libsvn_wc/status.c
handle_dir_entry subversion/libsvn_wc/status.c
get_dir_status subversion/libsvn_wc/status.c
svn_io_get_dirents2 subversion/libsvn_subr/io.c
entry_name_to_utf8 subversion/libsvn_subr/io.c
svn_path_cstring_to_utf8 subversion/libsvn_subr/path.c
svn_utf_cstring_to_utf8 subversion/libsvn_subr/utf.c * from here, bad node->handle
convert_cstring subversion/libsvn_subr/utf.c
convert_to_stringbuf subversion/libsvn_subr/utf.c * here, bad node => fail
В этот момент встречается тот факт, что Subversion использует libapr
(Apache Portable Runtime) для выделения памяти; и именно эта часть вызывает сбой - в основном, функция apr_xlate_conv_buffer
ведет себя по-разному в обоих случаях.
Но может быть довольно трудно понять, в чем здесь проблема, потому что apr_xlate_conv_buffer
использует кодировку в node->frompage
, которая установлена в определение APR_LOCALE_CHARSET 1
- и это не меняется между svn status
и Python. Чтобы вернуться к этому, я скопировал все, что связано с копированием и распределением строки APR, в стек вызовов и восстановил простой пример, который создает модуль Swig, который должен просто копировать строку с использованием среды выполнения APR; этот пример находится в каталоге aprtest , собранном с помощью скрипта bash build-aprtest.sh .
Благодаря этому примеру было выявлено, что проблему с ошибкой UTF можно решить, вызвав setlocale
в C перед любым выделением памяти строки APR - подробнее об этом тесте см. # 15977257 - Использование utf-8 вход для модуля Python cmd . Соответственно, все, что нам нужно сделать из Python - это выполнить:
import locale
locale.setlocale(locale.LC_ALL, '')
... перед любыми звонками на svn.client
(и, следовательно, на libsvn
, и, следовательно, на libapr
). И здесь у нас есть еще один пример, для поездки в отладчик, без действительно ошибки :)