Как отлаживать "Недопустимый параметр, переданный функции времени выполнения C"?

Фон

У меня есть терабайт файлов с необработанными данными с относительно небольшим подмножеством помеченных данных. Я написал код С++ (вызывающий некоторый древний код MSVС++ 2003, который я сильно модифицировал, чтобы его компилировать на последних компиляторах) для объединения аннотированных срезов данных.

Большая часть этих помеченных данных сосредоточена в одном файле, но этот файл оказывается тем, где моя программа вылетает.

Проблема

Я получаю

Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
terminate called after throwing an instance of 'int'

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

Что я пробовал

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

Мой вопрос

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

Существует ли общий метод, чтобы найти функцию C runtime, и что аргумент был? Я пропустил некоторые причудливые функции отладчика? Есть ли что-нибудь еще, что вы могли бы рекомендовать или информацию, которую я мог бы предоставить?

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

Конкретно для моей проблемы:

Моя трассировка стека выглядит следующим образом:

0 ntdll! DbgBreakPoint 0x7727000d
1 ntdll! DbgUiRemoteBreakin 0x772ff156
2?? 0x6f06eaa1
3 KERNEL32! BaseThreadInitThunk 0x7501338a
4 ntdll! RtlInitializeExceptionChain 0x77299902
5 ntdll! RtlInitializeExceptionChain 0x772998d5
6??

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

Попробовав еще пару функций, чтобы быть уверенным, что все дало таймаут, чтобы попытаться "backtrace" еще раз дать мне результат. Наверное, я просто никогда не ставил это много времени в gdb после того, как он однажды набросился на меня.

Тем не менее, я мог бы найти что-то с этой новой информацией. Подумайте, что моя проблема закрыта, но мой общий момент все еще верен. Я верю: теперь я нашел функцию с проблемой (я думаю), но не почему это проблема, и что это недопустимый параметр. Еще лучше, я проследил его до строки, где говорится "throw 1". Поэтому теперь я предполагаю, что windows/Qt переводит это в "недопустимый параметр". Но это неправда.

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

...

# 17 0x00c17d72 в libstdС++ - 6!.cxa_throw() из C:\Qt\5.5\mingw492_32\bin\libstdС++ - 6.dll Информация о таблице символов недоступна. ...

Ответ 1

Лично на терминале Linux я использую gcc для компиляции и gdb для отладки. Чтобы скомпилировать программу с параметрами отладки с помощью gcc, вам просто нужно добавить -g к другим флагам. Пример: gcc file.c -o file -std=c99 -g. Затем вы можете ввести gdb file и ввести интерактивный отладчик. Среди других полезных вещей вы можете запустить программу, вызвать функции и вставить точки останова. Для полного и хорошо объясненного использования перейдите на этот сайт - http://www.tutorialspoint.com/gnu_debugger/index.htm

Ответ 2

По крайней мере, в Visual Studio 2017 вы можете нажать CTRL + B и добавить _invalid_parameter останова функции в _invalid_parameter. Это остановит вашу программу в том месте, где сообщение было бы зарегистрировано, что позволит вам найти нарушающую функцию в стеке вызовов. Это будет работать, даже если кто-то другой код отменяет ваш вызов _CrtSetReportMode().

Ответ 3

Вещи, которые я узнал из этого вопроса (и это может помочь людям, которые ищут этот вопрос):

  • Оказывается, эта ошибка может быть прослежена до строки кода, в которой говорится: бросить 1;
    Это означает, что это может быть просто неправильный код, ему даже не нужно быть функцией C, и ничто не должно быть неправильным с вашими параметрами. Поиск вашего кода и источника библиотек для "throw"
  • Оказывается, что время ожидания на gdb не является индикатором чего-либо. Продолжайте попытки и повторите попытку, и, возможно, когда-нибудь вы сможете получить трассировку стека.

Ответ 4

Я столкнулся с тем же сообщением об ошибке "Invalid parameter..." при отладке драйвера Windows. Техника на этой странице, даже если для Windows, а не для адресации по этому вопросу, может оказаться полезной для тех, кто ищет это конкретное сообщение об ошибке. IOW HTH..

http://dennisyurichev.blogspot.com/2013/05/warning-invalid-parameter-passed-to-c.html

Итак, вы должны сузить специфику вашей среды, где выводится строка отладки, возможно, с помощью функции "вспомогательной" функции отладки. Как только вы знаете, установите контрольную точку там, а затем просмотрите стек вызовов. ИМХО, это очень умное решение для того, что может быть трудно найти.

Ответ 5

Поскольку журнал выводится на консоль отладки, он должен сообщаться функцией OutputDebugStringA. Вы можете установить точку останова на функцию, чтобы увидеть, кто приводит к этому журналу. Чтобы установить точку останова на функцию, вы можете Ctrl+B в Visual Studio и ввести имя функции:

enter image description here

Но это может не сработать, или вы можете записать слишком много других сообщений, используя OutputDebugStringA. Обычно Invalid parameter passed to C runtime function, сообщается _invalid_parameter, поэтому вы также можете попытаться установить _invalid_parameter останова в функции _invalid_parameter. Это может работать не так хорошо, потому что из какой-то другой системной dll может быть сообщено, что ваш процесс ссылается на: ntdll.dll, KernelBase.dll и т.д. Чтобы установить KernelBase.dll останова на функцию, экспортируемую dll, вам необходимо использовать: <dll>!<exportname>:

_invalid_parameter
ntdll.dll!__invalid_parameter
KernelBase.dll!__invalid_parameter
msvcrt.dll!__invalid_parameter
ucrtbase.dll!__invalid_parameter

Все это разные функции, и вы можете увидеть их адреса:

enter image description here

В моем случае только когда я установил точку останова на ntdll.dll!__invalid_parameter я смог увидеть обратную трассировку, и сообщение журнала было вызвано winapi GetAdaptersAddresses. Точка останова на OutputDebugStringA оказалась бесполезной, потому что журнал был напечатан через API DbgPrint. Размещение точки останова на DbgPrint работает в этом случае.