代码改变世界

使用_snscanf_s转换十六进制时引起的内存越界

2014-02-10 15:51  DVwei  阅读(915)  评论(0编辑  收藏  举报
//将Hex编码转换为指定编码格式的字符串
string Encoding::DecodeHexString(const string &strSrc, UINT code_page )
{
    string::size_type length = strSrc.length() / 2;
    char *result = new char[length + 1];
    ZeroMemory(result, length + 1);
    const char* str = strSrc.c_str();
    for(string::size_type i = 0; i < length; ++i)
    {
        _snscanf_s(str + (i * 2), 2, "%X", &result[i]);
    }

    string str = ConvertTo((char*)result, code_page);
    delete[] result;

    return str;
}

  此函数中,传入strtSrc参数是一个经过十六进制编码的字符串,此函数将每两个十六进制字符转换成一个十进制数,然后再转换未指定编码格式的字符串。

  从逻辑上看,这段代码没什么问题。但是程序运行到delete[] result;语句时就会出错,无法删除数组。

  因为经验不足,当时怎么想都没想明白。花了好几个小时调试才发现问题所在。

  _snscanf_s每次都往result写入4个字节(int),而result每个元素都是1字节,这就相当于一次写入了4个char。我的原意是每次输入一个1字节的十进制数。

  这就导致最后数组长度增加了3个字节,也就是发生了内存越界。delete操作也就出错了。

  修改后正确的代码应该是这样:

//将Hex编码转换为指定编码格式的字符串
string Encoding::DecodeHexString(const string &strSrc, UINT code_page )
{
    string::size_type length = strSrc.length() / 2;
    char *result = new char[length + 1];
    ZeroMemory(result, length + 1);
    const char* str = strSrc.c_str();
    int value = 0;
    
    for(string::size_type i = 0; i < length; ++i)
    {
        _snscanf_s(str + (i * 2), 2, "%X", &value);
        result[i] = value;
    }

    string str= ConvertTo((char*)result, code_page);
    delete[] result;

    return str;
}

  用一个4字节的int类型变量来接收输出参数,再赋值给result数组就可以了。int赋值给char这样做不就会发生截断吗?那么数据不就失真了么?

  是的,这样做会发生截断,但是不会失真。

  因为将字节流Hex编码的字符串时,每一个字节表示的数都会转换为unsigned char(1字节), 所以解码Hex字符串时所得到的数不可能超过255(1字节)。