【问题标题】:how to debug "Invalid parameter passed to C runtime function"?如何调试“传递给 C 运行时函数的无效参数”?
【发布时间】:2016-08-26 09:27:10
【问题描述】:

背景

我有大约 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 运行时函数列表可以筛选所有它们很慢,而且似乎没有帮助。

我的问题

“给一个人找一个bug,你帮他一天。教一个人调试,你帮他一辈子。在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 超时一次后从未在 gdb 中投入过这么多时间。

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

可能只是一些糟糕的代码,甚至不需要是 C 函数,也不需要你的参数有任何问题。

...

#17 0x00c17d72 in libstdc++-6!.cxa_throw () from C:\Qt\5.5\mingw492_32\bin\libstdc++-6.dll 没有可用的符号表信息。 ...

【问题讨论】:

  • Windows 弹出窗口出现的位置非常适合将调试器附加到进程 - 您应该会看到完整的堆栈跟踪。在附加之前不要关闭弹出窗口。
  • @AlanStokes 我什至尝试完全从 Qt 的调试器中运行它,但是 Qt 没有(或不知道)该文件的源代码,并向我展示了一些反编译的垃圾。我也没有得到堆栈跟踪。我会再次运行它来尝试截屏,也许我只是瞎了。
  • @AlanStokes 作为对您删除我的 C 标记的回应,我添加了它,因为它在技术上是 C++ 到 C 的通信错误(因为该错误专门引用“C 运行时函数”)。我不应该这样做吗?
  • 你在问一个 C++ 程序; C 运行时包含在 C++ 中(有各种修改)。你不是在问C;你只是碰巧提到了它。
  • @AlanStokes:很公平,感谢您的澄清。

标签: c++ debugging


【解决方案1】:

由于日志被打印到调试控制台,那么它应该由OutputDebugStringA 函数报告。您可以在函数上放置一个断点,以查看谁生成了该日志。要在函数上放置断点,您可以在 Visual Studio 中 Ctrl+B 并输入函数名称:

但这可能不起作用,或者您可能使用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

所有这些都是不同的功能,你可以看到它们的地址:

就我而言,仅当我在ntdll.dll!__invalid_parameter 上设置断点时,我才能看到回溯,并且日志消息是由GetAdaptersAddresses winapi 引起的。 OutputDebugStringA 上的断点没有帮助的原因是因为日志是通过 DbgPrint api 打印的。在这种情况下,在DbgPrint 上放置断点有效。

【讨论】:

  • 不幸的是没有帮助。但感谢您提供有关 ! 的信息;)
【解决方案2】:

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

【讨论】:

  • 也适用于 gdb (mingw)
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 我想感谢您的回答,它并没有真正给我任何新信息,但它可能会帮助其他用户,它让我再次尝试使用 gdb(之前超时)并最终导致我(部分)回答。由于我的名气不够,所以我不能投票给你,所以我想以这种方式告诉你。
    • 感谢您的意见,祝您找到完整的答案
    • 嘿,这个问题让我失望了,你得到了你应得的支持:D
    【解决方案5】:

    我在调试 Windows 驱动程序时遇到了同样的错误消息“无效参数...”。 此页面上的技术,即使适用于 Windows 并且不完全解决此问题,也可能对正在寻找此特定错误消息的人有用。 IOW HTH..

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

    因此,总而言之,您必须缩小特定于您的环境的范围,其中调试字符串可能由调试“帮助器”库函数输出。一旦知道,在那里设置一个断点,然后回顾调用堆栈。恕我直言,这是一个非常聪明的解决方案,可以解决难以找到的位置。

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-28
        • 1970-01-01
        • 1970-01-01
        • 2020-02-08
        • 1970-01-01
        • 2018-06-11
        • 1970-01-01
        相关资源
        最近更新 更多