将数据存储在char数组中导致变量周围损坏



我正在处理一个C++项目,遇到了一个问题。

下面是我的代码

tempfingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_TYPE_RSA);
char temp[48];
memset(temp, 0, sizeof(temp));
for (i = 0; i < 16; i++)
{
//fingerprintstream << (unsigned char)tempfingerprint[i] << ":";
if (temp[0] == 0)
{
sprintf(temp, "%02X:", (unsigned char)tempfingerprint[i]);
}
else
{
//sprintf(temp, "%s:%02X", temp, (unsigned char)tempfingerprint[i]);
char characters[3];
memset(characters, 0, sizeof(characters));
//If less than 16, then add the colon (:) to the end otherwise don't bother as we're at the end of the fingerprint
sprintf(characters, "%02X:", (unsigned char)tempfingerprint[i]);
strcat(temp, characters);
}
}
//Remove the end colon as its not needed. 48 Will already be null terminated, so the previous will contain the last colon
temp[47] = 0;
return string(temp);

当我运行我的应用程序时,我从visual studio 收到以下错误

Run-Time-Check Failure #2 - Stack around the variable 'temp' was corrupted. 

我通过Valgrind在Linux上运行了相同的代码,没有显示任何错误,所以我不确定Windows有什么问题。

以下是Paul McKenzie所说的一种方法(尽管他可能会以不同的方式实现),基于您试图使用流

#include <iostream>
#include <sstream>
#include <iomanip> // output format modifiers
using namespace std;
int main()
{
stringstream fingerprintstream;
// set up the stream to print uppercase hex with 0 padding if required
fingerprintstream << hex << uppercase << setfill('0');
// print out the first value without a ':'
fingerprintstream << setw(2) << 0;
for (int i = 1; i < 16; i++) // starting at 1 because first has already been handled.
{
// print out the rest prepending the ':'
fingerprintstream << ":" << setw(2) << i;
}
// print results
std::cout << fingerprintstream.str();
return 0;
}

输出:

00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F

我刚刚意识到OP在垃圾输出方面遇到了什么问题。输出数字时,<<将使用适当的转换来获取文本,但如果输出字符,<<将打印该字符。因此,fingerprintstream << (unsigned char)tempfingerprint[i];tempfingerprint[i]处取二进制值,并且由于强制转换,尝试将其渲染为字符。您将得到(假定ASCII)"a",而不是"97"。你试图打印的大量内容会给人一种胡言乱语的感觉。

示例:如果我更改

fingerprintstream << ":" << setw(2) << i;

fingerprintstream << ":" << setw(2) << (unsigned char)i;

输出变成

0?:0?:0?:0?:0?:0?:0?:0?:0?:0?:0 :0
:0?:0?:0
:0?:0?

注意选项卡和换行符。

我需要知道tempfingerprint的定义才能确定,但您可能可以通过删除强制转换来解决垃圾输出问题。

根据新信息,tempfingerprintconst char *,因此tempfingerprint[i]char,将打印为字符。

我们想要一个数字,所以我们必须强迫吸盘是一个整数。

static_cast<unsigned int>(tempfingerprint[i]&0xFF)

&0xFF屏蔽了除最后一个字节之外的所有字节,消除了负数在显示为无符号时向巨大正数的符号扩展。

据我所见,代码中有两个问题会导致超出数组边界:

首先,使用char temp[48],您正好保留48个字符用于存储结果;然而,当用第16个值调用strcat(temp, characters)时,并且characters至少包括包括冒号的字符,则temp将包括16*3个数字/冒号+一个终止的''字符,即49个字符(而不是48个)。请注意,strcat会自动附加一个以字符结尾的字符串。

其次,定义char characters[3],以便为两个数字和冒号保留位置,但不为终止的''字符保留位置。因此,sprintf(characters, "%02X:",...)将超过characters的数组边界,因为sprintf还附加了字符串终止符。

因此,如果您一般不想重写代码,那么将定义更改为char temp[49]char characters[4]将解决问题。

最新更新