从函数返回时保护char []的最佳方法是什么?

时间:2009-04-06 04:58:38

标签: c arrays

我正在维护一段C代码,其中char数组经常通过将它们传递给函数并将结果用作写入输出的字符串来填充。然而,在函数处理后,阵列上没有检查完成,我想知道最好的方法是什么?

一种方法是在返回数组后将数组中的最后一个元素设置为\ 0,但我怀疑可能有更好的元素。

void Unpack(char* inbuf, char* outbuf);

int main(int argc, char* argv[])
{
    char* inData = "abc";
    char outData[4];
    char result[14];

    Unpack(inData, outData);
    outData[3] = '\0';  // Insert this to safeguard array before using as string.

    _snprintf(result, sizeof(result), "blah %0s blah", outData);
    printf(result);

    return 0;
}

void Unpack(char* inbuf, char* outbuf) {
    for(int index=0; index<3; index++) {
        *outbuf++ = *inbuf++;
    } 
}

6 个答案:

答案 0 :(得分:5)

你解决这个问题的方法有很多,但不幸的是还有许多其他问题没有解决。

如果您担心输出数组中甚至可能没有有效的'\ 0'终止C字符串,那么您通过强力插入'\ 0'来解决该问题。此外,您已选择了最佳位置,如果数组应该包含'\ 0'终止字符串,则数组的最后一个字节不能用于其他任何内容。

不幸的是,你没有做任何事情来阻止被调用的函数践踏你已经为它分配的数组之外的内存。这是我担心的第一件事。

避免内存践踏(又称缓冲区溢出)并不是火箭科学,但确实需要纪律和一致性。通常,所涉及的基本思想是从不简单地传递要填充的某个存储器的地址,而是始终伴随该存储块的可用长度。当然,被叫代码必须遵守由此施加的限制。看起来你知道基本的想法,因为你提到了snprintf(),这是这种方法的典型例子。

答案 1 :(得分:4)

保护他们免受什么影响?如果你试图阻止缓冲区溢出等事情,那你就太晚了;您调用的函数具有完全访问权限和滥用权限,如果选择是“滥用”,您可以做的事情并不多。

答案 2 :(得分:4)

如果您拥有这两个代码,更好的方法是更改​​解包签名以传递输出缓冲区大小,因此它可以负责附加'\ 0'字符。

如果您无法控制Unpack,我会写一个薄层来完成工作。

unpack_safe(char *in, char* out, size_t len) {
  unpack(in, out);
  out[len-1]='\0';
}

使用此方法,您只能保护非空终止字符串,但如果您的字符串可以包含空字符,则这将无法按预期工作,并传递输入大小&amp;输出大小将是正确的行为。

答案 3 :(得分:3)

将最后一个元素设置为'\ 0'将正确终止字符串,但它不会修复函数在缓冲区外写入​​时所造成的损坏。在这种情况下,您只隐藏一个错误,程序可能会产生错误的结果,或者在完全无关的函数调用或返回时崩溃。

在我看来,最好检测一下函数是否写在它的缓冲区之外,如果它发生的话就会崩溃程序。这使得查找并因此更容易修复错误。为了实现这一点,你可以在调用函数和测试之前将缓冲区的最后一个字节设置为'\ 0'(使用assert()),如果函数返回时仍然如此。

而且,正如Bill Forster已经说过的那样,将缓冲区长度传递给被调用的函数总是一个好主意

答案 4 :(得分:1)

使用原始指针总是存在缓冲区溢出的可能性。使用包装类如std :: string,CString等总是安全的。

这适用于您编写的新代码。对于像这样的现有代码,你只能祈祷它不会崩溃。

答案 5 :(得分:1)

如果您担心像0x55AA这样的END-MARKER或某些保留字符。但是,如果您担心的是数据的完整性,您可以尝试使用一些校验和一些校验和CRC(循环冗余校验)。