【问题标题】:overflows in size_t additionssize_t 加法溢出
【发布时间】:2008-10-15 20:48:15
【问题描述】:

我希望我的代码对 VS.NET 和 GCC 没有警告,我希望我的代码准备好 64 位。

今天我写了一个小模块,它处理内存缓冲区并通过文件样式接口提供对数据的访问(例如,您可以读取字节、写入字节、四处寻找等)。

作为当前读取位置和大小的数据类型,我使用了 size_t,因为这似乎是最自然的选择。我绕过警告,它也应该在 64 位下工作。

以防万一:我的结构如下所示:

typedef struct
{
  unsigned char * m_Data;
  size_t          m_CurrentReadPosition;
  size_t          m_DataSize;
} MyMemoryFile;

size_t 的签名在实践中似乎没有定义。谷歌代码搜索证明了这一点。

现在我处于两难境地:我想用size_t 检查添加是否溢出,因为我必须处理用户提供的数据,而第三方库将使用我的代码。但是,对于溢出检查,我必须知道符号。它在实施中产生了巨大的差异。

那么 - 我到底应该如何以独立于平台和编译器的方式编写这样的代码?

我可以在运行或编译时检查size_t 的签名吗?那将解决我的问题。或者,size_t 一开始就不是最好的主意。

有什么想法吗?

编辑:我正在寻找 C 语言的解决方案!

【问题讨论】:

  • 您使用的是什么版本的 gcc?看起来他们在 2.4 之后(包括 2.4)的版本中使 size_t 未签名
  • 我要处理的版本到处都是。我做嵌入式编程,有时我不得不使用石器时代的编译器版本。
  • “签名”是常用词。

标签: c integer-overflow size-t


【解决方案1】:

关于 size_t 是签名还是未签名以及 GCC(来自旧的 GCC 手册 - 我不确定它是否仍然存在):

存在潜在问题 size_t 之前的 GCC 类型和版本 发布 2.4。 ANSI C 要求 size_t 始终是无符号类型。为了 与现有系统的兼容性 头文件,GCC 定义 size_tstddef.h 是任何类型 系统的sys/types.h 将其定义为 是。大多数 Unix 系统定义 size_tsys/types.h 中,将其定义为 是有符号的类型。中的一些代码 库依赖于 size_t 是 无符号类型,并且不会工作 如果签名正确。

期望的 GNU C 库代码 size_t 未签名是正确的。这 size_t 定义为有符号类型 是不正确的。我们计划在版本中 2.4,GCC 将始终将size_t 定义为无符号类型,并且 'fixincludes' 脚本将按摩 系统的sys/types.h以免 与此冲突。

与此同时,我们正在解决这个问题 通过明确告诉 GCC 来解决问题 对size_t 使用无符号类型 编译 GNU C 库。 “配置”会自动检测 GCC 用于size_t 的类型是什么? 必要时覆盖它。

如果您想要size_t 的签名版本,请使用ptrdiff_t,或者在某些系统上,ssize_t 有一个 typedef。

【讨论】:

  • 出于我自己的好奇心,我不得不这样做 - 我很难相信 GCC 会在没有适当解释的情况下忽视标准的一个非常基本的部分。
【解决方案2】:

size_t 是无符号整数类型,根据 C++ C 标准。任何带有size_t 签名的实现都严重不符合标准,并且可能还有其他可移植性问题。溢出时保证回绕,这意味着你可以编写像if (a + b < a)这样的测试来查找溢出。

size_t 是处理任何涉及内存的优秀类型。你做得对。

【讨论】:

    【解决方案3】:

    size_t 应该是无符号的。

    通常定义为 unsigned long。

    我从未见过它被其他定义。 ssize_t 是它的签名对应物。

    编辑: GCC 在某些情况下将其定义为已签名。在 ASNI C 模式或 std-99 下编译应该强制它是无符号的。

    【讨论】:

    • GCC 将 size_t 定义为有符号 :(
    • 在 64 位窗口中不是无符号长 32 位吗?对 size_t 的假设不是很好。
    • g++ 4.2.3 将其定义为无符号。
    • 这个问题是如何在 2008 年出现的? (错误地)将 size_t 定义为已签名的 GCC 的最后一个版本在 10 多年前就已经过时了。
    【解决方案4】:

    对于 C 语言,使用IntSafe。也由 Microsoft 发布(不要与 C++ 库 SafeInt 混淆)。 IntSafe 是一组 C 语言函数调用,可以安全地执行数学运算和转换。 updated URL for intsafe functions

    【讨论】:

      【解决方案5】:

      使用safeint。它是由 Michael Howard 设计并从 Microsoft 开源发布的一个类。它旨在处理被确定为存在溢出风险的整数。所有溢出都转换为异常并进行处理。该类旨在使正确使用变得容易。

      例如:

      char CouldBlowUp(char a, char b, char c)
      {
         SafeInt<char> sa(a), sb(b), sc(c);
      
         try
         {
           return (sa * sb + sc).Value();
         }
         catch(SafeIntException err)
         {
            ComplainLoudly(err.m_code);
         }
      
         return 0;
      }
      

      在 Microsoft 内部,在 Office 等产品中也大量使用 safeint。

      参考: link text

      【讨论】:

      • 我无法使用 SaveInt。我是 C-only,并且 afaik saveint 也不能​​解决符号问题,因为它假定来自 msvc 的默认值。
      • 哦,对了,这个问题最初被标记为 C++。请参阅我对 C 语言库的其他答案。
      • 是的 - 我知道。对于那个很抱歉。我编辑了问题以确保我不会误导其他人。
      【解决方案6】:

      我不确定我是否完全理解这个问题,但也许你可以这样做:

      temp = value_to_be_added_to;
      
      value_to_be_added_to += value_to_add;
      
      if (temp > value_to_be_added_to)
      {
        overflow...
      }
      

      由于它会返回到较低的值,因此您可以轻松检查它是否溢出。

      【讨论】:

      • 如果 value_to_add 为负数怎么办?
      猜你喜欢
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-31
      相关资源
      最近更新 更多