【问题标题】:Detect pointer arithmetics because of LARGEADDRESSAWARE由于 LARGEADDRESSAWARE 检测指针算法
【发布时间】:2011-03-04 09:09:11
【问题描述】:

我想将我的应用程序切换到 LARGEADDRESSAWARE。需要注意的问题之一是指针运算,因为指针差异不能再表示为有符号 32b。

有什么方法可以自动找到大型 C++ 项目中的所有指针减法实例?

如果没有,是否有一些“最省力”的手动或半自动方法来实现这一点?

【问题讨论】:

  • 您的意思是您正在为具有 64 位地址空间的系统构建应用程序,但编译器仅使用 32 位指针?
  • "LARGEADDRESSAWARE" 是可执行文件头中的 Windows32 标志,它告诉操作系统可执行文件可以处理 32 位地址。没有它,您将获得 31 位地址(即最高位始终为 0),然后为操作系统保留地址空间的后半部分。

标签: c++ visual-studio pointers static-analysis


【解决方案1】:

仅当您有 2 个相距超过 20 亿字节 (2GB) 的指针时才会出现问题。这意味着您:

  • 两者都有非常大的数组 (> 2GB)
  • 或者您正在减去指向完全不同结构的指针

所以寻找这些特殊情况。

我认为在大多数情况下这不是问题。

【讨论】:

  • “或者您正在减去指向完全不同结构的指针” - 这是很容易发生的事情。我们有时在对对象进行排序时使用指向对象的指针作为辅助键,以确保排序顺序稳定。至于“寻找这些特殊情况”——除了查看每一段代码之外,我该如何寻找它们?
  • 比较指针不是问题,减去它们是,对于排序,比较指针应该足够了。此外,使用指针作为最终比较也不是一个好主意。我过去也这样做过,但这可能会产生问题(问题可能会变得难以重现,因为每次运行应用程序时指针都可能不同;相信我,我自己也遇到过几次这个问题)。尝试找到另一个特征(例如,行号、数据库键......)以获得稳定的排序。
  • > "比较指针不是问题,减去它们是问题,"不幸的是,在实现qsort的比较功能时,返回差异似乎很自然,我已经看过几次了。不错的评论,不幸的是,主要问题仍未得到解答 - 如何找到案例?代码库很大,仅仅记住它们是不可能找到所有案例的。需要一些系统的方法,无论是自动的还是手动的(系统代码审查)。解决方案可以是编译时、专用工具或运行时,带有一些工具。
  • 公平点:您可能最终得到a<b<c<dd-a < 0
  • 请注意,如果您减去两个指针,您将获得指针之间元素数量的“偏移量”。这适用于指向数组中元素的指针,但如果两个指针不相关,则会产生奇怪的结果。结果可能不是整数。假设您的指针指向一个 1000 字节的类。如果 ptr1 指向 50000,而 ptr2 指向 60100,那么减法可能会返回 10,但这是不正确的。见securecoding.cert.org/confluence/display/seccode/…
【解决方案2】:

由于我们的代码已经用 GCC 编译,我认为最快的方法可能是:

  • 构建 GCC
  • 创建 GCC 的自定义修改,以便在检测到指针减法时打印警告(或错误)
  • 构建项目并收集有关指针减法的所有警告

以下是需要对 GCC 进行的更改的概要:

将您的警告添加到:

  • c-typeck.c (pointer_diff函数)
  • cp/typeck.c(pointer_diff函数)。

除了直接检测指针减法之外,另一件要做的事情是检测首先将指针转换为整数类型然后将它们相减的情况。这可能会更困难,具体取决于您的代码结构,以防 (.intptr_t) 的正则表达式搜索。-.*-(.*intptr_t) 效果很好。

【讨论】:

    【解决方案3】:

    使用 64 位编译器编译代码并开启 Wp64。

    因为指针是 64 位宽,但 int、long、DWORD 等保持 32 位宽,您会收到将 ptrdiff_t 缩短为 int32_t 的警告

    【讨论】:

    • 这个答案是不相关的,因为它可以捕捉到如果您使用错误的类型来存储指针可能会出现的问题,但是如果您正在进行“危险的”指针减法/比较,它不会警告您。
    • 好主意。它不会找到将指针减法分配给 ptrdiff_t 的情况,但这些情况也是一个问题,因为 ptrdiff_t(Win32 上的 int)不足以表示指针差异 - 但可以通过文本搜索 ptrdiff_t 来搜索这些情况。真正的问题是代码中有太多这样的警告,解决每一个似乎都需要大量的工作,而且绝大多数都与 LARGEADDRESSAWARE 无关(我们无意将代码移植到 Win64)。跨度>
    • 您是否声称存在一种编译模式,其中 ptrdiff_t 不足以容纳两个指针之间的差异?听上去……嗯,很糟糕,因为那是那种类型的标准定义。 (我希望它在不同的编译模式下具有不同的大小。)
    【解决方案4】:

    PC-Lint 可以发现这类问题。

    查看http://gimpel-online.com/MsgRef.html,错误代码947:

    应用于指针的减法运算符 ——一种表达方式 在 p 和 q 都是指针的地方找到了形式 p - q。这是 在最大指针可以的情况下特别重要 溢出保存指针差异的类型。例如, 假设最大指针为 3 GB -1,并且 指针差异由 long 表示,其中 最大 long 是 2 GB -1。请注意,这两个数量都适合 在 32 位字内。然后从 a 中减去一个小指针 非常大的指针会在 long 代表指针的差异。反过来, 从一个小指针中减去一个非常大的指针可以产生 一个正数。

    【讨论】:

      【解决方案5】:

      不管有什么价值,我浏览了Microsoft compiler warning docs for VS2017 并搜索了所有涉及“签名”、“trunc”(截断)和“conv”(转换)的警告,它们高于警告级别 1。然后我通过 propsheet 为我们解决方案中的所有项目显式启用这些警告。要启用特定警告,请转到“C/C++ / 命令行 / 附加选项”并以 /wL#### 格式添加它们,其中 L 是您要为其分配的警告级别,#### 是警告编号。

      所以我想出了这个列表:

      / W14365 / W14018 / W14146 / W14245 / W14092 / W14287 / W14307 / W14302 / W14305 / W14306 / W14307 / W14306 / W14309 / W14310 / W14309 / W14310 / W14311 / W14312 / W14051 / W14055 / W14152 / w14239 /w14223 /w14242 /w14243 /w14244 /w14254 /w14267 /w14333 /w14334 /w14367 /w14686 /w14826

      请注意,我使用 /w1 是因为我们的全局警告级别已经下降到 1(不要评判我,这是遗留问题)。因此,当您将默认警告级别设置为 3 或更高时,其中一些警告已经启用。

      这导致了超过 88000 条警告,其中大部分是关于在使用 STL 的代码中使用 int 而不是 size_t 以及关于 Windows API 类型(如句柄、WPARAM 和 UINT_PTR 等)的转换。我只在 3rd 方库中发现了一些与实际指针算术相关的警告,但在上下文中看起来还不错。

      无论如何,我认为这个相关警告列表可能会对某人有所帮助。

      另外,请使用此答案中描述的工具:https://stackoverflow.com/a/22745579/9635694

      另一个选项是根据CppCoreGuideLines 运行内置代码分析。转到“主菜单/分析/配置代码分析/解决方案”并为您要分析的所有项目选择“C++核心检查原始指针规则”。然后“主菜单/分析/运行代码分析/解决方案”。当心:修改您的项目,需要很长时间才能构建并且可能会产生大量警告。您可能希望专注于 C26481“不要使用指针算术”和 C26485“无数组到指针衰减”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-02
        • 2011-04-01
        相关资源
        最近更新 更多