Как отлаживать "Недопустимый параметр, переданный функции времени выполнения 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
работает в этом случае.