G-WAN с валгриндом? Альтернативы?

G-WAN — это удобный способ запуска C-кода в Интернете «из коробки», но для меня он не работает с valgrind. (При запуске valgrind ./gwan появляется сообщение об ошибке Inconsistency detected by ld.so: rtld.c: 1292: dl_main: Assertion `_rtld_local._dl_rtld_map.l_libname' failed!, а затем программа закрывается; используется 64-разрядная версия Debian Jessie).

Возникает вопрос:
1) Предполагается ли, что G-WAN работает с valgrind?
2) Существуют ли какие-либо другие жизнеспособные варианты обнаружения ошибок памяти в коде C, работающем под G-WAN?


person ArtemGr    schedule 15.07.2013    source источник


Ответы (1)


Должен ли G-WAN работать с valgrind?

Мы протестировали Valgrind, и, хотя он многое делает правильно, он просто не подходит для задач с высоким уровнем параллелизма (даже низкий уровень параллелизма является проблемой для Valgrind).

жизнеспособные варианты для обнаружения ошибок памяти в коде C, работающем под G-WAN?

Используйте malloc() оболочки, предварительно выделенные пулы или, что еще лучше, используйте alloca(), чтобы в первую очередь избежать проблем с памятью.

Обратите внимание, что G-WAN обрабатывает неверные указатели в сценариях C без сбоя сервера, см.: http://gwan.ch/developers#crash

Этот глючный код:

int main(int argc, char *argv[])
{
   strcpy(0xBADC0DE, 0xBADC0DE);
   return 200;
}

... создаст что-то вроде следующего «изящного» отчета о сбое:

Script: crash_libc.c
 Client: 127.0.0.1
 Query : ?crash_libc

 Signal        : 11:Address not mapped to object
 Signal src    : 1:SEGV_MAPERR
 errno         : 0
 Thread        : 0
 Code   Pointer: 0000f5200b33 (module:/lib/libc.so.6, function:strcpy, line:0)
 Access Address: 00000badc0de

 Registers     : EAX=00000badc0de CS=00000033 EIP=0000f5200b33 EFLGS=000000010202
                 EBX=000000000001 SS=ec2d8ed4 ESP=0000f5ded828 EBP=0000f5dee020
                 ECX=000033323130 DS=ec2d8ed4 ESI=0000ec2d8f86 FS=00000033
                 EDX=000003b03c00 ES=ec2d8ed4 EDI=00000badc0de CS=00000033

 Module        :Function        :Line # PgrmCntr(EIP)  RetAddress  FramePtr(EBP)
      libc.so.6:          strcpy:     - 0000f5200b33 0000ec2d8f00   0000f5dee020
        servlet:            main:    37 0000ec2d8f00 00000042e10c   0000f5dee020        

И G-WAN доходит до того, что сообщает вам, где произошла ошибка в вашем исходном коде (см. Примеры Crash_xxx.c G-WAN), вместо того, чтобы убивать серверный процесс.

Если вы не хотите отлаживать код C, используйте Java или Scala (оба поддерживаются G-WAN) — вам потребуется гораздо больше памяти, потому что ваши данные останутся загруженными до тех пор, пока сборщик мусора не замедлит все, чтобы освободить то, что, по его мнению, может быть освобождены - но, по крайней мере, вы получите меньше ошибок, связанных с памятью, если таковые имеются.


По просьбе человека, задавшего вопрос, вот более подробная информация.

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

Печальная правда в том, что все они страдают от общих проблем, они:

  • обычно слишком медленны для поддержки параллелизма (основная проблема)
  • генерировать миллионы тривиальных предупреждений (и даже больше ложных предупреждений)
  • очень дорогие (это или коммерческие, конечно) и не всегда могут быть протестированы перед покупкой (!)

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

Отсюда вывод выше: старайтесь делать простой код, когда это возможно, и старайтесь предварительно выделять блоки, когда нужны более сложные стратегии.

Конечно, тот факт, что Linux LIBC настаивает на уничтожении приложений с (неперехватываемыми) сигналами abort, не помогает (это не позволяет программе восстановить или сбросить соответствующую трассировку), особенно для неаккуратного обнаружения Linux LIBC с двойным освобождением ( который ошибочно предполагает, что весь код использует функцию malloc(), когда программа использовала функцию malloc() один раз — что часто делается с помощью вызовов LIBC!). И я даже не говорю ни о сбоях mmap(), ни о выключателе OOM.

Единственное решение, которое мы пока нашли работающим, — это отказаться от использования Linux LIBC и компилировать все, что нам нужно, с помощью нашей собственной среды выполнения C. Это немного сложно рекомендовать как "то, что нужно сделать" для всех пользователей, но это сработало для нас.

Мы были бы очень рады, если бы части нашего кода (или хотя бы некоторые концепции, реализованные в G-WAN) использовались Linux, так как это значительно облегчило бы нашу жизнь (и жизнь многих других разработчиков), но контакты то, что мы имели в прошлом с «ответственными людьми», не было обнадеживающим.

В общем, есть возможности для улучшений со стороны ОС, таких независимых разработчиков программного обеспечения, как мы, и со стороны разработчиков — в конце концов, параллелизм является «только» основным с 2004 года... почти десять лет назад.

person Gil    schedule 16.07.2013
comment
Valgrind работает на ядре Signle, но отлаживает задания NP с высокой степенью параллелизма. Если у вас есть ошибка, вы всегда можете перенаправить часть трафика на сервер с valgrind. Обертки malloc LD_PRELOAD, такие как DUMA и ElectricFence, тоже не работают с G-WAN (DUMA падает сразу, EF в stream3.c). Обработка памяти не так проста, как alloca, когда вы имеете дело с асинхронным кодом, и даже с alloca каждая большая программа будет иметь ошибки и повреждения памяти, если это вообще возможно. Спасибо за Ваш ответ. Однако остается вопрос: что является рабочей альтернативой valgrind с G-WAN? - person ArtemGr; 16.07.2013
comment
Я добавлю больше деталей в ответ выше, но вкратце (действительно способные) инструменты отладки параллелизма в настоящее время коммерчески недоступны. - person Gil; 17.07.2013
comment
Еще раз спасибо за ответ, Гил. Однако ваше недовольство сценой на самом деле не является решением проблемы отладки кода. Как насчет -fsanitize=address в новых компиляторах, планируете ли вы поддерживать это в G-WAN? - person ArtemGr; 17.07.2013
comment
Наше разочарование прекратилось, когда мы перестали полагаться на Linux LIBC. И -fsanitize убивает хост-процесс после сообщения о первой ошибке (точно так же, как LIBC), демонстрируя при этом своим единственным существованием, что в королевстве есть ожидающие решения проблемы. Кроме того, распределитель памяти G-WAN быстрее, безопаснее и не умирает из-за вызовов double-free или других NOP, и он может сообщать, привязан ли указатель к выделенному блоку или нет (сообщая размер блока). .. не убивая процесс. - person Gil; 18.07.2013
comment
Наличие висячего указателя — это поведение undefined, вы не хотите, чтобы такой процесс работал, это может привести к неустранимому повреждению данных. Valgrind и -fsanitize позволяют обнаружить ошибку там, где она произошла, или, по крайней мере, ближе к этому месту. Это особенность этих инструментов, а не проблема. Они используются для тестирования кода (см. cplusplusmusings .wordpress.com/2013/03/20/), чтобы ошибочный код не работал круглосуточно и без выходных. Возвращаясь к G-WAN, как пользовательский код будет проверять, привязан ли указатель к выделенному блоку? Что это за функция? Спасибо. - person ArtemGr; 18.07.2013
comment
ArtemGr пишет: Висячий указатель — это поведение undefined, вы не хотите, чтобы такой процесс работал. Если только у вас нет способа проверить указатели перед вызовом free() или перед их разыменованием — и это то, что позволяет нам делать распределитель G-WAN. Мы не экспортировали эти возможности для скриптов, потому что люди полагаются на библиотеки, которые делают скрытые вызовы malloc() (например, LIBC), и единственный способ справиться с этими указателями — передать их в LIBC malloc()/free(). , с неразрешимыми проблемами, которые вы описали. - person Gil; 19.07.2013
comment
Если у вас нет способа проверить указатели перед вызовом free() или перед их разыменованием - это не делает висячие указатели безопасными. - person ArtemGr; 19.07.2013
comment
Это абсолютно так - когда ваши вызовы API встраивают эту логику прозрачно для вызывающих. Обратите внимание, что это был полный смысл перезаписи распределителя системной памяти. - person Gil; 20.07.2013
comment
Нет, двойное освобождение — не единственная проблема с оборванными указателями. - person ArtemGr; 20.07.2013
comment
Перечитайте то, что я написал, и вы увидите, что наш распределитель памяти обращается ко всем остальным смертельным случаям — ни разу не убивая процесс. - person Gil; 20.07.2013
comment
Вы только написали, что ваш распределитель памяти проверяет, освобожден ли уже указатель, чтобы предотвратить ошибки двойного освобождения. Я не вижу упоминания о том, что ваш распределитель проверяет доступ ко всем указателям, чтобы предотвратить повреждение данных висячим указателем и обнаружить его на ранней стадии, как это проверяют valgrind или -fsanitize. - person ArtemGr; 20.07.2013
comment
Я написал: он может сообщать, прикреплен ли указатель к выделенному блоку или нет (сообщая размер блока), и это позволяет нашему коду проверять, является ли указатель действительным или нет. - person Gil; 20.07.2013
comment
У меня это есть, но мне, разработчику программного обеспечения, это никак не помогает. Если в моем коде или коде библиотеки, которую я использую, есть висячий указатель, G-WAN не обнаружит его. - person ArtemGr; 20.07.2013
comment
«Изящные» отчеты о сбоях G-WAN обнаруживают и сообщают о неверных указателях (см. обновленный ответ выше)... если только LIBC не примет иного решения и не завершит процесс G-WAN с помощью невосстанавливаемого сигнала ABORT. Отсюда мое замечание выше, что если Linux примет часть кода (или концепций) G-WAN, то это сделает нашу жизнь (и жизнь многих других разработчиков) намного проще. В то же время ничто не заменит отладку (или использование JVM или CLR), но это не вина G-WAN. - person Gil; 20.07.2013
comment
Приятно знать. То, что я вижу в «изящных» отчетах о сбоях G-WAN, не сильно отличается от пользовательского обработчика SIGSEGV, выполняющего раскручивание стека или присоединяющего GDB к убитому процессу. Я использую такие обработчики, с google-coredumper, например, и они помогают. Однако это не замена valgrind или fsanitize, потому что сбойный код может незаметно повредить данные, если произойдет запись в область памяти, сопоставленную с доступной для записи страницей памяти. Вам нужны охранные регионы, чтобы поймать это. ср. code.google.com/p/address-sanitizer/wiki/ - person ArtemGr; 20.07.2013
comment
Если вы не хотите отлаживать код C, используйте Java или Scala — я нужно отлаживать свой код, и я хочу делать это с помощью лучших доступных инструментов . - person ArtemGr; 20.07.2013
comment
Лучший доступный инструмент — это ваш мозг. Не ждите, что библиотека или трассировщик волшебным образом решат все проблемы — этим инструментам еще предстоит пройти долгий путь, чтобы стать более актуальными. Как было сказано ранее, существуют способы избежать условий, которые приводят к неустранимым ошибкам памяти, но до тех пор, пока Linux LIBC (среда выполнения системы) остается в стороне от этих концепций, вам придется ударься головой о клавиатуру, чтобы продолжить... и решай эти бессмысленные проблемы. Что делает новые идеи необходимыми сегодня, так это дополнительная сложность, вызванная проблемами параллелизма. Время на стороне инструментов, которые помогают. - person Gil; 22.07.2013
comment
Самый лучший доступный инструмент — это ваш мозг. Статично известный факт, что даже самый лучший мозг создает ошибки. Не ждите, что библиотека или трассировщик волшебным образом все решит — это не волшебство, это проверенная технология. Valgrind много раз помогал мне, он очень полезен для точного определения места ошибки и тестирования нового кода. Как было сказано ранее, есть способы избежать условий, которые приводят к фатальным ошибкам памяти. Как уже говорилось ранее, автоматическое управление памятью (RAII и shared_ptr) не так просто с кодом, управляемым событиями. - person ArtemGr; 23.07.2013
comment
Я не вижу ни технической ценности этого последнего философского комментария, ни вопроса в нем, отсюда отсутствие у меня какого-либо осмысленного ответа. Ваш первоначальный вопрос был о подходящих альтернативах Valgrind (который не подходит для параллельных задач), и я ответил, насколько мне известно. Обратите внимание, что никто не чувствовал, что можно дать лучший ответ, так что не только у меня такие смешанные чувства. - person Gil; 24.07.2013