在工作中,我们一直在尝试弄清楚这段代码的作用,并且我们认为它可能会引起问题。这是C语言中的hashmap实现。
static thrift_map_node_t *thrift_map_newnode (thrift_map_base_t *m, union keyDataTypes key, void * value, int vsize)
thrift_map_node_t *node;
int ksize = strlen(key) + 1;
int voffset = ksize + ((sizeof(void*) - ksize) % sizeof(void*));
node = malloc(sizeof(*node) + voffset + vsize);
if (!node) return NULL;
memcpy(node + 1, key, ksize);
node->hash = thrift_hash(key);
node->value = ((char*) (node + 1)) + voffset;
memcpy(node->value, value, vsize);
return node;
我们认为的问题在这里
int voffset = ksize + ((sizeof(void*) - ksize) % sizeof(void*));
我们认为这可能会产生负值,例如C中的-9%4 = -1。
一个变通办法或对它正在尝试做的任何帮助都将是不错的。
答案 0 :(得分:4)
否,如果size_t
的排名高于或等于int
,它就不可能永远产生负值(并且也许除了在某些带有32位整数的真正奇怪的16位寻址系统上),因为那样
sizeof (void*) - ksize
的类型为size_t
,它是无符号类型,并且始终为正。因此,如果void指针的宽度为8个字节,而ksize的宽度为17,则在64位计算机上,相减的结果为(size_t)-9
或18446744073709551607。该模8为7,将其加到17将得到24,这是sizeof (void *)
的倍数。
但是,这取决于sizeof (void *)
是 2的幂,因此,如果您使用的话,效果会更好
sizeof (void*) - (ksize + sizeof (void*)) % sizeof (void *)
用于填充,因为这完全避免了负数
尽管将减去结果是 ,这是事实,因为C99的模数始终为负:(-3) % 4
为-3
例子。
顺便说一句,代码不应使用sizeof (void *)
,而应使用_Alignof (void *)
。
代码中还有另外一件事值得怀疑。假设某人实际上可以输入长度超过2 GiB的字符串-那么在大多数平台上都会发生签名溢出,而且看起来不会很漂亮!