Как искать Heisenbug

Существует большое общее ядро C (особенно C89) и C++, но существуют несомненно области различия между C и C++. Очевидно, C++ имеет все объектно-ориентированные функции, плюс универсальное программирование, плюс исключения, плюс пространства имен, которые не делает C. Однако существуют также функции C, которые не находятся в C++, таком как поддержка (близко к архаичному) нотация непрототипа для объявления и определения функций. В частности, значение следующего объявления функции отличается в C и C++:

extern void function();

В C++, который является функцией, которая не возвращает значения и не берет параметров (и, поэтому, назван только для его побочных эффектов, независимо от того, что они). В C, который является функцией, которая не возвращает значения, но для которого нет никакой информации о списке аргументов. C все еще не требует объявления в объеме, прежде чем функция будет вызвана (в целом; у Вас должно быть объявление в объеме, если функция берет список переменных аргументов, таким образом, это очень важно для #include <stdio.h> перед использованием printf(), и т.д.).

существуют также различия:

sizeof('c')

В C++, ответ равняется 1; в C ответ обычно равняется 4 (32-разрядные системы с 8-разрядными символами) или даже 8 (64-разрядные системы с 64-разрядным интервалом).

В целом, можно записать код, который скомпилирует и под C и под компиляторами C++ без большой трудности - большинство моего кода делает это все время. Исключениями является или результат небрежности с моей стороны, или потому что я сознательно использовал хорошие функции C99, которые не находятся в C++ 98, таком как обозначенные инициализаторы, или long long.

7
задан onnodb 17 October 2009 в 14:37
поделиться

10 ответов

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

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

Последний будет затронут из-за изменения времени между уровнями оптимизации. Первое, как правило, гораздо более вероятно.

Если у вас есть какой-то автоматизированный способ заполнить только что выделенную память неким постоянным значением до того, как оно будет передано программе, и это заставит сбой исчезнуть или стать воспроизводимым в отладочной сборке , это будет хорошей отправной точкой для начала погони.

12
ответ дан 6 December 2019 в 05:55
поделиться

Одна простая вещь - включить предупреждение и подсказку компилятора, пересобрать проект и затем исправить все предупреждения / подсказки

Ура

2
ответ дан 6 December 2019 в 05:55
поделиться

Если вы знаете, каким будет формат даты и времени, вы также можете использовать DateTime .. ::. TryParseExact Method

DateTime.TryParse может вызвать проблемы, когда он используется с датами, например, 01/03/2009

Это 01 марта или 3 января?

Я бы предпочел порекомендовать вам использовать что-то другое, кроме текстового поля, например, средство выбора даты, или проверить текстовое поле, чтобы у вас было что-то вроде дд МММ гггг. очень редко вы ошибаетесь с этим.

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

Небольшое заблуждение, потому что кажется, что вы довольно легко нашли своего «Гейзенберга». Теперь проблема в том, как с этим справиться, и ответ - просто явно инициализировать вашу запись, чтобы вы не зависели от того, какое поведение или побочный эффект компилятора иногда заботится об этом за вас, а иногда нет.

Поставленный вопрос теперь немного вводит в заблуждение, потому что кажется, что вы довольно легко нашли своего «Гейзенберга». Теперь проблема в том, как с этим справиться, и ответ - просто явно инициализировать вашу запись, чтобы вы не зависели от того, какое поведение или побочные эффекты компилятора иногда заботятся об этом за вас, а иногда нет.

Поставленный вопрос теперь немного вводит в заблуждение, потому что кажется, что вы довольно легко нашли своего «Гейзенберга». Теперь проблема в том, как с этим справиться, и ответ - просто явно инициализировать вашу запись, чтобы вы не зависели от того, какое поведение или побочные эффекты компилятора иногда заботятся об этом за вас, а иногда нет.

3
ответ дан 6 December 2019 в 05:55
поделиться

Вполне может быть проблема памяти и регистра: вы программируете нормально, полагаясь на постоянство памяти после освобождения.
Я бы рекомендовал запускать ваше приложение с FastMM4 в режиме полной отладки, чтобы быть уверенным в управлении памятью.
Другой (не бесплатный) инструмент, который может быть очень полезен в таком случае, - это Eurekalog.

Еще одна вещь, которую я видел: сбой с ошибками регистров FPU при вызове внешнего кода (DLL, COM ...), в то время как с отладчиком все было в порядке.

6
ответ дан 6 December 2019 в 05:55
поделиться

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

2
ответ дан 6 December 2019 в 05:55
поделиться

Especially in purely native languages, like Delphi, you should be more than careful not to abuse the freedom to be able to cast anything to anything. IOW: One thing, I have seen is that someone copies the definition of a class (e.g. from the implementation section in RTL or VCL) into his own code and then cast instances of the original class to his copy. Now, after upgrading the library where the original class came from, you might experience all kinds of weird stuff. Like jumping into the wrong methods or bufferoverflows.

There's also the habit of using signed integer as pointers and vice-versa. (Instead of cardinal) this works perfectly fine as long as your process has only 2GB of address space. But boot with the /3GB switch and you will see a lot of apps that start acting crazy. Those made the assumption of "pointer=signed integer" at least somewhere. Your customer uses a 64Bit Windows? Chances are, he might have a larger address space for 32Bit apps. Pretty tough to debug w/o having such a test system available.

Then, there's race conditions. Like having 2 threads, where one is very, very slow. So that you instinctively assume it will always be the last one and so there's no code that handles the scenario where "Captn slow" finishes first. Changes in the underlying technologies can make these assumptions very wrong, very fast indeed. Take a look at the upcoming breed of Flash-based super-mega-fast server storage. Системы, которые могут читать и писать гигабайты в секунду. Приложения, которые предполагают, что ввод-вывод выполняется значительно медленнее, чем некоторые вычисления значений в памяти, легко потерпят неудачу на таком быстром хранилище.

Я мог бы продолжать и продолжать, но мне нужно запустить прямо сейчас ... Ура

2
ответ дан 6 December 2019 в 05:55
поделиться

Является ли это локальной переменной внутри процедуры или функции?

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

- jeroen

1
ответ дан 6 December 2019 в 05:55
поделиться

В таких случаях я всегда советую использовать файлы журнала.

Вопрос: Можете ли вы каким-то образом определить неправильное отображение в исходном коде?

Если нет, то мой ответ не поможет.

Если да, проверьте неточность и, как только обнаружите, сбросьте стек в файл журнала. (см. посмертную отладку для получения подробной информации о дампе и изменении символов стека).

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

1
ответ дан 6 December 2019 в 05:55
поделиться

Если это бизнес-код Delphi с компонентами, ориентированными на данные, и т. Д., Следующее может не применяться.

Однако я пишу код машинного зрения, который требует немного вычислительных ресурсов. Большинство юнит-тестов основаны на консолях. Я также занимаюсь FPC и за эти годы много тестировал с FPC. Частично из-за хобби, частично в отчаянных ситуациях, когда я хотел хоть немного догадаться.

Некоторые стандартные уловки, которые я пробовал (уменьшение полезности)

  1. , используют -gv и valgrind кода (практически это означает, что приложения должны запускаться на Linux / FreeBSD. Но для вычислительного кода и модульных тестов, которые могут быть выполнены)
  2. компилировать с использованием fpc param -gt (= мусор локальных переменных, рандомизировать локальные переменные при инициализации процедуры)
  3. изменять диспетчер кучи для рандомизации данных блоков, которые он выводит (также применимо к коду Delphi)
  4. Попробуйте FPC ' s проверка диапазона / переполнения и подсказки компилятора.
  5. запускается на Mac Mini (powerpc) или win64. Из-за совершенно разных правил и схем памяти он может улавливать довольно странные вещи.

2 и 3 вместе почти позволяют найти большинство, если не все проблемы инициализации.

Попробуйте найти какие-либо подсказки, а затем вернитесь к Delphi и поиск более сфокусированы, отладка и т. Д.

Я понимаю, что это непросто. У меня большой опыт работы с FPC, и мне не пришлось искать все с нуля для этих случаев. Тем не менее, возможно, стоит попробовать, и это может быть мотивацией для начала настройки невизуальных систем и юнит-тестов, совместимых с FPC и независимых от платформы. Большая часть этой работы все равно потребуется, если посмотреть на дорожную карту Delphi.

Из-за совершенно разных правил и схем памяти он может улавливать довольно забавные вещи.

2 и 3 вместе почти позволяют найти большинство, если не все проблемы инициализации.

Попробуйте найти какие-либо подсказки, а затем вернитесь к Delphi и поиск более сфокусированы, отладка и т. Д.

Я понимаю, что это непросто. У меня большой опыт работы с FPC, и мне не пришлось искать все с нуля для этих случаев. Тем не менее, возможно, стоит попробовать, и это может быть мотивацией для начала настройки невизуальных систем и юнит-тестов, совместимых с FPC и независимых от платформы. Большая часть этой работы в любом случае потребуется, если посмотреть на дорожную карту Delphi.

Из-за совершенно разных правил и схем памяти он может улавливать довольно странные вещи.

2 и 3 вместе почти позволяют найти большинство, если не все проблемы инициализации.

Попробуйте найти какие-либо подсказки, а затем вернитесь к Delphi и поиск более сфокусированы, отладка и т. Д.

Я понимаю, что это непросто. У меня большой опыт работы с FPC, и мне не пришлось искать все с нуля для этих случаев. Тем не менее, возможно, стоит попробовать, и это может быть мотивацией для начала настройки невизуальных систем и юнит-тестов, совместимых с FPC и независимых от платформы. Большая часть этой работы в любом случае потребуется, если посмотреть на дорожную карту Delphi.

Я понимаю, что это непросто. У меня большой опыт работы с FPC, и мне не пришлось искать все с нуля для этих случаев. Тем не менее, возможно, стоит попробовать, и это может быть мотивацией для начала настройки невизуальных систем и юнит-тестов, совместимых с FPC и независимых от платформы. Большая часть этой работы в любом случае потребуется, если посмотреть на дорожную карту Delphi.

Я понимаю, что это непросто. У меня большой опыт работы с FPC, и мне не пришлось искать все с нуля для этих случаев. Тем не менее, возможно, стоит попробовать, и это может быть мотивацией для начала настройки невизуальных систем и юнит-тестов, совместимых с FPC и независимых от платформы. Большая часть этой работы все равно потребуется, если посмотреть на дорожную карту Delphi.

2
ответ дан 6 December 2019 в 05:55
поделиться

Given your description of the problem I think you had uninitialized data that you got away with without the optimizer but which blew up with the optimization on.

0
ответ дан 6 December 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: