在调用memset()
时,我的一些代码中出现了一些奇怪的,间歇性的数据中止(<5%的时间)。问题是,除非代码运行了几天,否则通常不会发生,因此很难在行为中发现它。
我正在使用以下代码:
char *msg = (char*)malloc(sizeof(char)*2048);
char *temp = (char*)malloc(sizeof(char)*1024);
memset(msg, 0, 2048);
memset(temp, 0, 1024);
char *tempstr = (char*)malloc(sizeof(char)*128);
sprintf(temp, "%s %s/%s %s%s", EZMPPOST, EZMPTAG, EZMPVER, TYPETXT, EOL);
strcat(msg, temp);
//Add Data
memset(tempstr, '\0', 128);
wcstombs(tempstr, gdevID, wcslen(gdevID));
sprintf(temp, "%s: %s%s", "DeviceID", tempstr, EOL);
strcat(msg, temp);
正如你所看到的,我并没有尝试使用尺寸大于最初用malloc()
分配的memset
有人看到这可能有什么问题吗?
答案 0 :(得分:21)
malloc
可以返回NULL
。你没有检查它。
答案 1 :(得分:4)
有几件事。你正在使用本身不安全的sprintf
;除非你100%肯定你不会超过缓冲区的大小,否则你应该总是更喜欢snprintf
。这同样适用于strcat
;更喜欢更安全的替代strncat
。
显然,这可能无法解决任何问题,但它采用长的方式来帮助发现可能会发现可能非常烦人的错误。
答案 2 :(得分:3)
如果没有内存,malloc可以返回NULL 可用。你没有检查 这一点。
对,你是......我没有想到这一点,因为我正在监视记忆,而且有足够的免费。有没有办法在系统上有可用的内存,但是malloc失败了?
是的,如果内存碎片化。此外,当您说“监视内存”时,系统上可能会有某些内容偶尔消耗大量内存,然后在您发现之前将其释放。如果您对
malloc
的呼叫发生,则不会有任何可用内存。 - Joel
无论哪种方式......我都会加上检查:)
答案 3 :(得分:1)
wcstombs
没有得到目的地的大小,所以理论上它可以缓冲溢出。
为什么你使用sprintf
我认为是常量?只需使用:
EZMPPOST" " EZMPTAG "/" EZMPVER " " TYPETXT EOL
C和C ++将字符串文字声明组合成一个字符串。
答案 4 :(得分:0)
你尝试过使用Valgrind吗?这通常是调试这些错误的最快速,最简单的方法。如果您正在读取或写入超出已分配内存的范围,它将为您标记它。
答案 5 :(得分:0)
你正在使用sprintf 本质上不安全;除非你是100% 积极的,你不会 超过缓冲区的大小,你 应该几乎总是喜欢snprintf。 这同样适用于strcat;更喜欢 更安全的替代strncat。
是的.....我最近主要做.NET,老习惯很难。我可能会把这段代码从我之前写的其他东西中拉出来......
但是我将来会尝试不使用那些;)
答案 6 :(得分:0)
你知道它甚至可能不是你的代码......是否还有其他正在运行的程序会导致内存泄漏?
答案 7 :(得分:0)
它可能是你的处理器。某些CPU无法处理单个字节,并且要求您使用单词或块大小,或者具有只能用于字或块对齐数据的指令。
通常编译器会知道这些并解决它们,但有时您可以将一个区域作为字节malloc,然后尝试将其作为结构或宽于一个字节的字段来解决,编译器赢了“抓住它,但处理器稍后会抛出数据异常。
除非您使用的是异常CPU,否则不会发生这种情况。例如,ARM9会这样做,但i686不会。我看到它被标记为windows mobile,所以也许你有这个CPU问题。
答案 8 :(得分:0)
您应该使用malloc
来清除新分配的内存,而不是memset
后跟calloc
。除此之外,做乔尔所说的。
答案 9 :(得分:0)
NB从其他答案中借鉴了一些评论并整合到一起。代码全是我的......
此代码执行相同的操作,安全,运行速度更快,占用内存更少。
// sizeof(char) is 1 by definition. This memory does not require zero
// initialisation. If it did, I'd use calloc.
const int max_msg = 2048;
char *msg = (char*)malloc(max_msg);
if(!msg)
{
// Allocaton failure
return;
}
// Use snprintf instead of sprintf to avoid buffer overruns
// we write directly to msg, instead of using a temporary buffer and then calling
// strcat. This saves CPU time, saves the temporary buffer, and removes the need
// to zero initialise msg.
snprintf(msg, max_msg, "%s %s/%s %s%s", EZMPPOST, EZMPTAG, EZMPVER, TYPETXT, EOL);
//Add Data
size_t len = wcslen(gdevID);
// No need to zero init this
char* temp = (char*)malloc(len);
if(!temp)
{
free(msg);
return;
}
wcstombs(temp, gdevID, len);
// No need to use a temporary buffer - just append directly to the msg, protecting
// against buffer overruns.
snprintf(msg + strlen(msg),
max_msg - strlen(msg), "%s: %s%s", "DeviceID", temp, EOL);
free(temp);