оптимизированы параметры strncpy C++; перезаписывает случайную память

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

Вызов внешней библиотеки (FUSE) strncpy "случайно" перезаписывает shared_ptr<mutex> в моем коде, что вызывает ошибку сегментации, когда я пытаюсь заблокировать этот мьютекс. Я запустил свою программу с помощью valgrind, и она не обнаружила никаких ошибок памяти (флаги valgrind ниже). Когда я запускаю свой код в gdb и устанавливаю точку наблюдения на этом shared_ptr, он прерывается при вызове strncpy. gdb говорит, что все параметры strncpy (dest, src и nbytes) были «оптимизированы», что заставляет меня думать, что для этого вызова используется неинициализированная память. Я правильно интерпретирую это? Любая идея, что может быть причиной?

Вот трассировка стека из gdb при перезаписи указателя:

#0  __strncpy_ssse3 () at ../sysdeps/x86_64/multiarch/strcpy-ssse3.S:2482
#1  0x0000003245809094 in strncpy (__len=<optimized out>, __src=<optimized out>, __dest=<optimized out>) at /usr/include/bits/string3.h:120
#2  add_name (buf=<optimized out>, bufsize=<optimized out>, s=<optimized out>, name=<optimized out>) at fuse.c:907
#3  0x000000324580997c in try_get_path (f=<optimized out>, nodeid=<optimized out>, name=<optimized out>, path=<optimized out>, wnodep=<optimized out>, need_lock=<optimized out>) at fuse.c:956
#4  0x000000324580a281 in get_path_common (f=<optimized out>, nodeid=<optimized out>, name=<optimized out>, path=<optimized out>, wnode=<optimized out>) at fuse.c:1152
#5  0x0000003245812432 in fuse_lib_unlink (req=<optimized out>, parent=<optimized out>, name=<optimized out>) at fuse.c:1198
#6  0x0000003245817057 in fuse_ll_process_buf (data=0x6f5650, buf=0x7fffffffd850, ch=<optimized out>) at fuse_lowlevel.c:2441
#7  0x000000324581388f in fuse_session_loop (se=0x6f8410) at fuse_loop.c:40
#8  0x000000324580b698 in fuse_loop (f=<optimized out>) at fuse.c:4309
#9  0x000000324581bb8f in fuse_main_common (argc=<optimized out>, argv=<optimized out>, op=<optimized out>, op_size=<optimized out>, user_data=<optimized out>, compat=<optimized out>) at helper.c:355
#10 0x000000000046f1b6 in main (argc=4, argv=0x7fffffffdec8) at ../src/fuse.cpp:100 

Вот аргументы, с которыми я запустил valgrind:

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes

person br1ckd    schedule 16.04.2013    source источник
comment
Попробуйте скомпилировать без оптимизаций.   -  person AShelly    schedule 16.04.2013
comment
Какая версия FUSE?   -  person Drew Dormann    schedule 16.04.2013
comment
@Drew: FUSE версии 2.6, я думаю, что это последняя версия   -  person br1ckd    schedule 16.04.2013
comment
@AShelly: оптимизация уже отключена (флаг -O0)   -  person br1ckd    schedule 16.04.2013
comment
@ user1091954 FUSE 2.6 выпущен в 2006 году. Мои поисковые запросы в Интернете показывают несколько похожих сбоев в более старых версиях, чем в самой новой, то есть 2.9.2. Дайте мне знать, поможет ли обновление, и я опубликую его как ответ.   -  person Drew Dormann    schedule 16.04.2013
comment
Может быть, я все время использовал 2.9.2. Я использовал любую версию, которую предоставляют репозитории Fedora Core 18. Я изменил определение FUSE_USE_VERSION с 26 на 29, но я все еще получаю ошибку.   -  person br1ckd    schedule 16.04.2013
comment
Чтобы уточнить, я проверил, что в настоящее время использую 2.9.2.   -  person br1ckd    schedule 16.04.2013
comment
@KeithThompson Это вызывается из библиотеки FUSE, я ничего не могу сделать.   -  person br1ckd    schedule 21.04.2013


Ответы (2)


Эта ошибка возникла в результате создания shared_ptr с new, затем приведения его к типу weak_ptr и удаления.

person br1ckd    schedule 19.04.2013
comment
Приведение общего указателя к типу? И компилятор позволяет это сделать? Фуууу. - person Michael Dorgan; 20.04.2013
comment
Я использую библиотеку C, и она предоставляет только uint64_t для хранения дескриптора. Я передаю библиотеке структуру, содержащую указатель на слабый указатель, преобразованный в uint64_t. Библиотека вызывает мои функции и передает им структуру, содержащую указатель на слабый указатель. Я случайно установил указатель (приведенный как uint64_t) на адрес общего указателя вместо слабого указателя. - person br1ckd; 21.04.2013

gdb говорит, что все параметры strncpy (dest, src и nbytes) были «оптимизированы», что заставляет меня думать, что для этого вызова используется неинициализированная память. Я правильно интерпретирую это?

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

Вот простой пример:

int
mystrcpy(char *p, const char *q)
{
    while (*p++ = *q++);
}

скомпилированный с -g -O0, вы видите, что он сразу же сбрасывает свои аргументы в стек:

mystrcpy:
.LFB0:
        .file 1 "t.c"
        .loc 1 5 0
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movq    %rdi, -8(%rbp)      <<< here
        movq    %rsi, -16(%rbp)     <<< and here
        ...

Затем компилятор сгенерировал отладочную информацию об этом:

    .section        .debug_info
    ...
    .uleb128 0x7
    .string "p"   <<< from char *p
    .byte   0x1
    .byte   0x4
    .long   0x65
    .byte   0x2
    .byte   0x91
    .sleb128 -24  <<< not 100% sure but this is probably related to frame offset
    .uleb128 0x7
    .string "q"
    .byte   0x1
    .byte   0x4
    .long   0x72
    .byte   0x2
    .byte   0x91
    .sleb128 -32   <<< note adjacent to p

Когда вы запускаете -O2 -g, несмотря на -g, функция становится намного меньше:

mystrcpy:
.LFB11:
        .file 1 "t.c"
        .loc 1 5 0
        .cfi_startproc
        (at this point we start copying, using the input regs directly)

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

person Ben Jackson    schedule 20.04.2013