首页 > 解决方案 > sprintf() 出错:'__builtin___sprintf_chk' 可能会在目标末尾写入终止 nul

问题描述

我正在尝试按照本指南为 RX 制作工具链。该指南使用以下工具:

GCC-4.6.4
binutils-2.23.52
gdb-7.6
newlib-2.0.0

当我运行第一个make时,我遇到了这个错误:

../../binutils-2.23.52/binutils/prdbg.c:500:20: 错误: '__builtin___sprintf_chk' 可能会在目标 [-Werror=format-overflow=]
sprintf (buf , "%ld", (long) vma);

然后我打开代码并导航到这应该有错误的部分:

static void
print_vma (bfd_vma vma, char *buf, bfd_boolean unsignedp, bfd_boolean hexp)
{
  if (sizeof (vma) <= sizeof (unsigned long))
    {
      if (hexp)
    sprintf (buf, "0x%lx", (unsigned long) vma);
      else if (unsignedp)
    sprintf (buf, "%lu", (unsigned long) vma);
      else
    sprintf (buf, "%ld", (long) vma); // <-- this line
    }
    // ... // some code below

我搜索并找到了这些问题:question 1question 2。我知道这个溢出错误是因为缓冲区不够大,无法包含所有数据。但是这个链接指出两者都long具有unsigned long相同的存储大小(8 字节)。

我尝试替换longunsigned long并且它通过了,这个文件上没有更多错误(所以我认为下面的代码没有相关错误)但我认为这不是一个好方法。

所以,我真的不明白为什么long会导致错误而unsigned long不会。还是我误解了什么?谢谢您的帮助。


ps:实际上在这个错误之前,我首先遇到了这两个错误(在其他文件中):

但它们与这个错误无关(我修复了它们)所以我跳过了。

标签: c

解决方案


unsigned long的存储大小可能是 8 个字节,但字符串中的十进制表示可能更长!

例如,2^32适合 4 个字节,但字符串表示"4294967296"需要 11 个字节(注意隐含的零字节作为字符串终止符)!因此,您需要为目标提供大于 8 个字节的缓冲区sprintf()

一般来说,ceil(log_10(max_value_of_datatype)) + 1 (zero byte)十进制字符串表示需要字节(根据符号的不同,减号可能需要一个额外的字节)。

对于 64 位无符号值,这会导致 ceil(log_10(2^64)) + 1 = 21 bytes

64 位有符号的结果相同:ceil(log_10(2^63)) + 1 + 1 (for minus sign) = 21 bytes.

对于 32 位无符号值,这会导致ceil(log_10(2^32)) + 1) = 11 bytes,而对于 32 位有符号值,必要的空间是ceil(log_10(2^31)) + 2) = 12 bytes


推荐阅读