使用 Str(n)cat 的 Pebble 堆损坏
Pebble Heap Corruption With Str(n)cat
在更新我的 Pebble 表盘的电池显示时,我通过我的 toString 函数将电池电量输入 s_battery_level,运行(它在 100% 的时间内工作,我已经对其进行了测试),然后附加一个 % 和一个空终止符,只是为了更好地衡量。但是,出于某种原因,当该行为 运行 时,当电池电量从 100% 下降到 90%(或 100 下降到任何较低的数字)时,我会收到堆损坏错误。我在空终止符中尝试了 removing/adding,同时使用了 strcat() 和 strncat(),甚至转义了 %,但似乎没有任何效果。一旦我删除了有问题的行,它就完美地工作了。
为什么这行会破坏堆?或者,我怎么能 fix/avoid 呢?
static void battery_update_proc(Layer *layer, GContext *ctx) {
graphics_context_set_text_color(ctx, TxtColor);
char * lvl = calloc(6,sizeof(char));
lvl = toString(s_battery_level, lvl);
//strncat(lvl, "%[=10=]", 2);
//offending line above ^
APP_LOG(APP_LOG_LEVEL_DEBUG, "%s", lvl);
graphics_draw_text(ctx, lvl, s_txt_font, GRect(bound.origin.x + ROUND_OFFSET_BA_X, bound.size.h * .5 + ROUND_OFFSET_BA_Y, bound.size.w, 24), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}
为了更好地衡量,这里是 toString 函数:
char * toString(int value, char * result) {
int digit = digits(value);
result = calloc(digit + 1, sizeof(char));
result[digit] = '[=11=]';
int usedVal = 0;
for (int i = digit; i > 0; i--)
{
int x = (value - usedVal) / pwrOf10(i - 1);
result[digit - i] = (char) x + '0';
usedVal = usedVal + (result[digit - i] - '0') * pwrOf10(i - 1);
}
return result;
}
int digits(int n) {
if (n < 0) return digits((n == 0) ? 9999 : -n);
if (n < 10) return 1;
return 1 + digits(n / 10);
}
int pwrOf10(int power) {
int val = 1;
int i = power;
while (i > 0)
{
val *= 10;
i--;
}
return val;
}
您为 lvl
分配了两次内存 - 一次在 battery_update_proc
中,然后在 toString
中再次分配。这是第二次出现问题,因为它只为数字分配了足够的 space。
然后你没有 free
ing 任何一块内存,所以你也有内存泄漏。
至于如何修复它,为什么不直接用 sprintf(lvl,"%d%%",s_battery_level)
替换对 toString
的调用,然后记得在函数末尾调用 free(lvl)
。
问题的最终答案是我必须修改 toString 以在 calloc() 调用中添加额外的 space。感谢所有提醒我该技术细节的人!
在更新我的 Pebble 表盘的电池显示时,我通过我的 toString 函数将电池电量输入 s_battery_level,运行(它在 100% 的时间内工作,我已经对其进行了测试),然后附加一个 % 和一个空终止符,只是为了更好地衡量。但是,出于某种原因,当该行为 运行 时,当电池电量从 100% 下降到 90%(或 100 下降到任何较低的数字)时,我会收到堆损坏错误。我在空终止符中尝试了 removing/adding,同时使用了 strcat() 和 strncat(),甚至转义了 %,但似乎没有任何效果。一旦我删除了有问题的行,它就完美地工作了。
为什么这行会破坏堆?或者,我怎么能 fix/avoid 呢?
static void battery_update_proc(Layer *layer, GContext *ctx) {
graphics_context_set_text_color(ctx, TxtColor);
char * lvl = calloc(6,sizeof(char));
lvl = toString(s_battery_level, lvl);
//strncat(lvl, "%[=10=]", 2);
//offending line above ^
APP_LOG(APP_LOG_LEVEL_DEBUG, "%s", lvl);
graphics_draw_text(ctx, lvl, s_txt_font, GRect(bound.origin.x + ROUND_OFFSET_BA_X, bound.size.h * .5 + ROUND_OFFSET_BA_Y, bound.size.w, 24), GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}
为了更好地衡量,这里是 toString 函数:
char * toString(int value, char * result) {
int digit = digits(value);
result = calloc(digit + 1, sizeof(char));
result[digit] = '[=11=]';
int usedVal = 0;
for (int i = digit; i > 0; i--)
{
int x = (value - usedVal) / pwrOf10(i - 1);
result[digit - i] = (char) x + '0';
usedVal = usedVal + (result[digit - i] - '0') * pwrOf10(i - 1);
}
return result;
}
int digits(int n) {
if (n < 0) return digits((n == 0) ? 9999 : -n);
if (n < 10) return 1;
return 1 + digits(n / 10);
}
int pwrOf10(int power) {
int val = 1;
int i = power;
while (i > 0)
{
val *= 10;
i--;
}
return val;
}
您为 lvl
分配了两次内存 - 一次在 battery_update_proc
中,然后在 toString
中再次分配。这是第二次出现问题,因为它只为数字分配了足够的 space。
然后你没有 free
ing 任何一块内存,所以你也有内存泄漏。
至于如何修复它,为什么不直接用 sprintf(lvl,"%d%%",s_battery_level)
替换对 toString
的调用,然后记得在函数末尾调用 free(lvl)
。
问题的最终答案是我必须修改 toString 以在 calloc() 调用中添加额外的 space。感谢所有提醒我该技术细节的人!