《编写高质量代码:改善c程序代码的125个建议》—— 建议14-1:尽量避免对未知的有符号数执行位操作

本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第2章,建议14-1,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

建议14-1:尽量避免对未知的有符号数执行位操作

在C语言中,如果在未知的有符号数上执行位操作,很可能会导致缓冲区溢出,从而在某些情况下导致攻击者执行任意代码,同时,还可能会出现出乎意料的行为或编译器定义的行为。
下面来看一个简单的示例,如代码清单2-3所示。

代码清单2-3 在未知的有符号数上执行位操作示例
#include <stdio.h>
int main (void)
{
    int x=0;
    int y=0x80000000;
    char buf[sizeof("128")];
    x=sprintf(buf,"%u",y>>24);
    if(x==-1||x>=sizeof(buf))
    {
            // 错误处理
    }
    printf(buf);
    return 0;
}

在代码清单2-3中,y>>24的执行结果为4294967168,而sizeof(buf)的结果为4。当我们将y>>24的结果值转换为字符串“4294967168”时,超出了buf范围,所以结果值无法完全存储在buf中。因此,在执行语句“x=sprintf(buf,"%u",y>>24)”时,sprintf方法在进行写操作时就会越过buf的边界,从而产生缓冲区溢出。
如果在编译器VC++中执行这段程序,将会产生如图2-4所示的错误报告。
在C99中,要修正这样的错误,最好利用snprintf方法来代替sprintf方法。因为snprintf方法最多从源串中复制n-1个字符到目标串中,然后再从后面加一个0。因此,如果目标串的大小为n,将不会产生
溢出。
当然,如果将变量y声明成为无符号类型,那么这种缓冲区溢出错误将不会发生,如代码清单2-4所示。

代码清单2-4 代码清单2-3的改进示例
#include <stdio.h>
int main (void)
{
    int x=0;
    unsigned int y=0x80000000;
    char buf[sizeof("128")];
    x=sprintf(buf,"%u",y>>24);
    if(x==-1||x>=sizeof(buf))
    {
        // 错误处理
    }
    printf(buf);
    return 0;
}
上一篇:有哪些常用的 Python 标准库?


下一篇:Java工程师该如何编写高效代码?