我们有两个无符号计数器,我们需要比较它们以检查一些错误情况:
uint32_t a, b;
// a increased in some conditions
// b increased in some conditions
if (a/2 > b) {
perror("Error happened!");
return -1;
}
问题是a
和b
有一天会溢出。如果a
溢出,它仍然可以。但如果b
溢出,那将是一个误报。如何使这个检查防弹?
我知道让a
和b
uint64_t
延迟这种误报。但它仍然无法完全解决这个问题。
===============
让我澄清一点:计数器用于跟踪内存分配,这个问题可以在dmalloc/chunk.c找到:
#if LOG_PNT_SEEN_COUNT
/*
* We divide by 2 here because realloc which returns the same
* pointer will seen_c += 2. However, it will never be more than
* twice the iteration value. We divide by two to not overflow
* iter_c * 2.
*/
if (slot_p->sa_seen_c / 2 > _dmalloc_iter_c) {
dmalloc_errno = ERROR_SLOT_CORRUPT;
return 0;
}
#endif
答案 0 :(得分:6)
我认为你误解了代码中的评论:
我们除以2而不是溢出
iter_c * 2
。
无论值来自哪里,写a/2
都是安全的,但写a*2
是不安全的。无论您使用的是哪种无符号类型,都可以将数字除以2,而相乘可能会导致溢出。
如果条件如下:
if (slot_p->sa_seen_c > _dmalloc_iter_c * 2) {
然后大约一半的输入会导致错误的情况。话虽这么说,如果你担心计数器溢出,你可以将它们包装在一个类中:
class check {
unsigned a = 0;
unsigned b = 0;
bool odd = true;
void normalize() {
auto m = std::min(a,b);
a -= m;
b -= m;
}
public:
void incr_a(){
if (odd) ++a;
odd = !odd;
normalize();
}
void incr_b(){
++b;
normalize();
}
bool check() const { return a > b;}
}
请注意,为了完全避免溢出,您必须采取其他措施,但如果a
和b
增加或减少相同的数量,这可能已经没问题了。
答案 1 :(得分:4)
注意发生溢出。
uint32_t a, b;
bool aof = false;
bool bof = false;
if (condition_to_increase_a()) {
a++;
aof = a == 0;
}
if (condition_to_increase_b()) {
b++;
bof = b == 0;
}
if (!bof && a/2 + aof*0x80000000 > b) {
perror("Error happened!");
return -1;
}
每个a, b
相互依赖地具有2个 32 + 1个反映值和条件增量的不同状态。不知何故,需要超过uint32_t
的信息。可以使用uint64_t
,变体代码路径或辅助变量,例如bool
。
答案 2 :(得分:4)
发布的代码实际上似乎没有使用可能包含的计数器。
代码中的评论是说比较a/2 > b
而不是a > 2*b
更安全,因为后者可能会溢出而前者无法溢出。 a
的类型尤其如此b
的类型。
答案 3 :(得分:2)
通过强制它们同时换行,在值换行时将值标准化。在它们包裹时保持两者之间的差异。
尝试这样的事情;
uint32_t a, b;
// a increased in some conditions
// b increased in some conditions
if (a or b is at the maximum value) {
if (a > b)
{
a = a-b; b = 0;
}
else
{
b = b-a; a = 0;
}
}
if (a/2 > b) {
perror("Error happened!");
return -1;
}
答案 4 :(得分:1)
如果即使使用64位还不够,那么你需要编写自己的代码" var increase"方法,而不是重载++
运算符(如果你不小心可能会弄乱你的代码)。
该方法只需将var重置为' 0'或其他一些有意义的价值。
答案 5 :(得分:1)
如果您的目的是确保行动x
的发生频率不超过行动y
的两倍,我建议您采取以下措施:
uint32_t x_count = 0;
uint32_t scaled_y_count = 0;
void action_x(void)
{
if ((uint32_t)(scaled_y_count - x_count) > 0xFFFF0000u)
fault();
x_count++;
}
void action_y(void)
{
if ((uint32_t)(scaled_y_count - x_count) < 0xFFFF0000u)
scaled_y_count+=2;
}
在许多情况下,可能需要减少增量scaled_y_count
时使用的比较中的常数,以限制可以“存储”多少action_y
次操作。但是,即使操作次数超出uint32_t
的范围,上述操作也应该在操作保持接近2:1比例平衡的情况下正常工作。