如何调试“传递给C运行时函数的无效参数”?

时间:2016-05-01 15:35:04

标签: c++ debugging

背景

我有大约1 TB的原始数据文件,标记数据的子集相对较小。我编写了c ++代码(调用了一些古老的MSVC ++ 2003代码,我对其进行了大量修改以使其在最近的编译器上进行编译)来聚合带注释的数据切片。

标记数据的很大一部分集中在一个文件中,但该文件最终成为程序崩溃的文件。

问题

我正在

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

在我的Qt输出窗口中,Windows在弹出窗口中告诉我相同的内容,但此时从可执行文件/调试程序中获取任何有用的信息为时已晚(尽管我对Qt没有任何经验)调试器)。

我尝试了什么

我已经搜索了所有人,发现很多人都有这个错误消息,但它是如此通用,以至于他们的问题都没有和我的一样,并且有很长的不同C运行时函数列表可以筛选所有它们很慢,似乎没什么帮助。

我的问题

“找一个男人一个小虫,你帮他一天。教一个男人去调试,你帮他一辈子。在stackoverflow上发帖,你帮助很多男人并获得很多赞成。”

是否有一个通用方法来查找问题的C运行时函数以及参数是什么?我错过了一些花哨的调试器功能吗?还有什么可以推荐或我可以提供的信息吗?

我希望得到一个全能的答案来帮助每个人解决这个问题,而不仅仅是我,但如果我当然得到帮助,我会很高兴。

特定于我的问题:

我的堆栈跟踪如下:

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

并且gdb似乎无法获得更好的跟踪(我尝试用它做的任何事都会导致超时错误)。

尝试了几个函数之后,确保一切都超时尝试“回溯”再一次给了我一个结果。我想我曾经在我这里耽搁过一次之后,就再也没有把这么多时间花在gdb上了。

那就是说,我可能能够找到这个新信息。考虑我的具体问题已经关闭,但我的一般观点仍然有效我相信:我现在已经找到了问题的函数(我认为),但不是为什么它是一个问题,也不是无效参数是什么。更好的是,我已经将它追溯到一条线,上面写着“扔1”。所以现在我假设windows / Qt将其转换为“无效参数”。但事实并非如此。

它可能只是一些错误的代码,它甚至不需要是一个C函数,并且您的参数不需要出错。

...

#17 0x00c17d72在libstdc ++中 - 6!.cxa_throw()来自C:\ Qt \ 5.5 \ mingw492_32 \ bin \ libstdc ++ - 6.dll 没有符号表信息。 ...

6 个答案:

答案 0 :(得分:6)

至少在Visual Studio 2017中,您可以按CTRL + B并在_invalid_parameter上添加函数断点。这将使您的程序停在记录消息的位置,这将使您在调用堆栈中找到有问题的功能。即使其他人的代码撤消了您对_CrtSetReportMode()的调用,它也将起作用。

答案 1 :(得分:4)

就个人而言,在Linux终端上,我使用gcc进行编译,使用gdb进行调试。要使用gcc编译带有调试选项的程序,只需在其他标志中添加-g即可。实施例:gcc file.c -o file -std=c99 -g。然后,您可以键入gdb file,然后进入交互式调试器。除了其他有用的东西,你可以运行程序,调用函数和插入断点。有关完整且解释清楚的用法,请访问此网站 - http://www.tutorialspoint.com/gnu_debugger/index.htm

答案 2 :(得分:4)

由于日志已打印到调试控制台,因此应该通过OutputDebugStringA函数进行报告。您可以在函数上放置一个断点,以查看谁在该日志中生成结果。要在函数上设置断点,可以在Visual Studio中Ctrl+B并输入函数名称:

enter image description here

但是这可能不起作用,或者您可能使用OutputDebugStringA记录了太多其他消息。通常Invalid parameter passed to C runtime function_invalid_parameter报告,因此,您最好尝试在_invalid_parameter函数上放置一个断点。这可能无法正常工作,因为它可能会从您的进程链接到的其他系统dll中报告:ntdll.dllKernelBase.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上设置断点时,我才能看到回溯,并且日志消息是由GetAdaptersAddresses winapi引起的。 OutputDebugStringA上的断点之所以没有帮助,是因为该日志是通过DbgPrint API打印的。在这种情况下,可以在DbgPrint上设置断点。

答案 3 :(得分:2)

我从这个问题中学到的东西(这可能有助于人们搜索这个问题):

  1. 事实证明,这个错误可以追溯到一行代码说明 扔1;
    这意味着它可能只是一些糟糕的代码,它甚至不需要是一个C函数,并且您的参数不需要出错。搜索代码和库的源代码“throw”
  2. 事实证明,在gdb上获取超时不是任何指示。继续尝试并重试,也许有一次你可能会得到一个堆栈跟踪。

答案 4 :(得分:0)

在调试Windows驱动程序时,我遇到了同样的错误消息“Invalid parameter ...”。 此页面上的技术,即使对于Windows而言并不完全针对此问题,也可能对正在查找此特定错误消息的人有用。 IOW HTH ..

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

总而言之,您必须根据可能的调试“帮助”库函数输出调试字符串的环境进行缩小。一旦知道,在那里设置断点,然后查看调用堆栈。恕我直言,这是一个非常聪明的解决方案,可以找到一个难以找到的位置。

答案 5 :(得分:0)

如果仅使用MinGW(没有Visual Studio构建的东西)。构建调试版本时,请尝试为控制台子系统而不是Windows子系统编译应用程序。在这种情况下,当将无效参数传递给C函数时,该函数将失败并将触发您的错误处理代码,而不是标准库的错误框,这将使您更好地控制正在发生的事情。