【问题标题】:sizeof dereferenced pointer is undetermined?sizeof 取消引用的指针未确定?
【发布时间】:2016-09-17 05:18:18
【问题描述】:

Linux内核中的代码(可能是驱动):

https://us.codeaurora.org/cgit/quic/la/kernel/msm/tree/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c?id=38110df3021daf7740018f4b5cc61423c7382aac

检查 *data_ptr 的大小

sizeof(*data_ptr)

像这样:

uint32_t *data_ptr = cfg_data +
        reg_cfg_cmd->u.rw_info.cmd_data_offset/4;

    if ((UINT_MAX - sizeof(*data_ptr) <
                reg_cfg_cmd->u.rw_info.reg_offset) ||
                (resource_size(vfe_dev->vfe_mem) <
                reg_cfg_cmd->u.rw_info.reg_offset +
                sizeof(*data_ptr))) {
                    pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__);
                    return -EINVAL;
                }

是大小

uint32_t *data_ptr

不确定?好像应该永远是4个字节。


更新:

如果是,那是什么意思

UINT_MAX - sizeof(*data_ptr)

?

其实是安全检查,这里出现漏洞。代码稍后修补:

https://us.codeaurora.org/cgit/quic/la//kernel/msm/commit/?id=8ad163e831a2b2c30551edb360f168a604cdb0bb

【问题讨论】:

  • Yes sizeof(*data_ptr) 应该始终为 4。但最好使用 sizeof 而不是硬编码为 4。例如,如果 data_ptr 的类型发生变化,则使用 @987654330 的代码@ 无需更改即可工作,但如果将其替换为硬编码值,则不会。
  • 补丁通过引入代码重复使代码变得更糟(uint32_t 出现两次,因此如果有人更改数据类型,错误检查可能与代码不同步)。似乎该补丁具有将错误检查提升到不同位置的正确想法,但它不应该对sizeof 表达式进行此特定更改。此外,整本书很难阅读,我个人会将其排版,以便读者一眼就能验证支票。
  • 那是一个丑陋的...如果声明就在那里。肯定是 Linux 内核。

标签: c linux pointers driver sizeof


【解决方案1】:

不,它可能不是四个字节。标准(即 ISO)C 中的一个字节不一定是八位。当指代一个特定的八位项目时,标准通常会使用术语“八位位组”。

字节是最小尺寸的自然数据元素。如果这是 16 位数据类型,那么 int32_t 的大小将是 2 而不是 4。

鉴于 Linux 及其同类运行的架构种类繁多,您可能应该允许诸如此类的变化。考虑到 C 代码经常进入完全不同的系统的可能性,如果可能的话,通常最好有可移植的代码(尤其是如果它不花钱的话)。

【讨论】:

  • 鉴于 POSIX 要求 8 位字节,我不完全确定情况是否如此。当然,您可以使用不同的编译器构建用户空间,但我怀疑内核/用户界面会变得非常混乱。
  • @MatteoItalia,Linux 不符合 POSIX,但我会澄清一下,我说的是 real C 标准 :-)
  • stdint 类型的目的是为原生原始数据类型提供合理的替代方案。我认为假设一个字节不是 8 位是没有意义的。相反,我强烈鼓励每个人编写在某个字节不是 8 位的古怪 DSP 系统上执行时神秘地中断或崩溃的代码。不鼓励使用 1980 年代蹩脚的 DSP 架构,你将为人类带来好处。
  • 无论如何,这不是 sizeof 运算符存在的原因......它只是提供自记录代码而不是“幻数”。
  • @Lundin,这是一种观点。我自己,我渴望我们抛弃奇怪的 UTF-8 编码标准并且字符是完整的 32 位宽的日子。当那一天到来时,我所有的代码仍然可以工作。好吧,尽管它曾经起作用了 :-) 但是,说真的,你在某一方面是正确的。如果您只对定位特定设备感兴趣,您可以对它们做出假设。这完全取决于可移植性和易于开发之间的权衡。
【解决方案2】:

不是不确定,确实是四个字节。然而,阅读sizeof(*data_ptr) 而不是4 在代码中更清晰,因为只看到数字,读者可能会想知道4 的来源。请参阅this wikipedia article 了解有关魔术常数主题的讨论。

【讨论】:

    【解决方案3】:

    我相信这是由可移植性引起的:始终避免使用硬编码值。 Sizeof() 在编译期间起作用,因此在执行期间没有开销。

    【讨论】:

      【解决方案4】:

      sizeof(*data_ptr) 是取消引用指针的大小。我大胆猜测uint32_t 是一个无符号的 32 位 int,即 4 个字节。 sizeof(uint32_t*) 为您提供指针的大小,这取决于您的架构(32 位系统为 4 字节,64 位系统为 8 字节)。

      【讨论】:

      • uint32_t 由 C 标准定义。它是一个无符号的 32 位 int(但不一定是 4 bytes ,因为某些系统的字节大小不是 8)。
      • @M.M 有趣.. 没听说过
      • @M.M 根据我的经验,一个字节一直是 8 位。我发现了这一点,convo 建议只有旧的遗留系统具有不同的字节大小:stackoverflow.com/questions/13615764/is-a-byte-always-8-bits。我还发现这个说更新的 PCIe 有一个 10 位字节:quora.com/Why-is-one-byte-8-bits-even-on-a-16-or-32-bit-machine。只是好奇您是否有任何字节!= 8位的情况/示例。这是否适用于如今的大多数嵌入式芯片?
      猜你喜欢
      • 2020-11-10
      • 1970-01-01
      • 2017-01-26
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-11
      • 2013-01-04
      相关资源
      最近更新 更多