Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c2176e4

Browse files
committed
Fix the internals of our hash functions to used unsigned values during hash
computation as the overflow behavior of signed integers is undefined. NOTE: This change is smaller compared to 3.2 as much of this cleanup had already been done. I added the comment that my change in 3.2 added so that the code would match up. Otherwise this just adds or synchronizes appropriate UL designations on some constants to be pedantic. In practice we require compiling everything with -fwrapv which forces overflow to be defined as twos compliment but this keeps the code cleaner for checkers or in the case where someone has compiled it without -fwrapv or their compiler's equivalent. Found by Clang trunk's Undefined Behavior Sanitizer (UBSan). Cleanup only - no functionality or hash values change.
2 parents c0dd80e + 27cbcd6 commit c2176e4

4 files changed

Lines changed: 12 additions & 12 deletions

File tree

Include/pyport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ Used in: PY_LONG_LONG
145145
#endif
146146

147147
/* Prime multiplier used in string and various other hashes. */
148-
#define _PyHASH_MULTIPLIER 1000003 /* 0xf4243 */
148+
#define _PyHASH_MULTIPLIER 1000003UL /* 0xf4243 */
149149

150150
/* Parameters used for the numeric hash implementation. See notes for
151151
_Py_HashDouble in Objects/object.c. Numeric hashes are based on

Objects/setobject.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ NULL if the rich comparison returns an error.
7777
static setentry *
7878
set_lookkey(PySetObject *so, PyObject *key, register Py_hash_t hash)
7979
{
80-
register size_t i;
80+
register size_t i; /* Unsigned for defined overflow behavior. */
8181
register size_t perturb;
8282
register setentry *freeslot;
8383
register size_t mask = so->mask;
@@ -159,7 +159,7 @@ set_lookkey(PySetObject *so, PyObject *key, register Py_hash_t hash)
159159
static setentry *
160160
set_lookkey_unicode(PySetObject *so, PyObject *key, register Py_hash_t hash)
161161
{
162-
register size_t i;
162+
register size_t i; /* Unsigned for defined overflow behavior. */
163163
register size_t perturb;
164164
register setentry *freeslot;
165165
register size_t mask = so->mask;
@@ -760,7 +760,7 @@ static Py_hash_t
760760
frozenset_hash(PyObject *self)
761761
{
762762
PySetObject *so = (PySetObject *)self;
763-
Py_uhash_t h, hash = 1927868237U;
763+
Py_uhash_t h, hash = 1927868237UL;
764764
setentry *entry;
765765
Py_ssize_t pos = 0;
766766

@@ -775,11 +775,11 @@ frozenset_hash(PyObject *self)
775775
hashes so that many distinct combinations collapse to only
776776
a handful of distinct hash values. */
777777
h = entry->hash;
778-
hash ^= (h ^ (h << 16) ^ 89869747U) * 3644798167U;
778+
hash ^= (h ^ (h << 16) ^ 89869747UL) * 3644798167UL;
779779
}
780-
hash = hash * 69069U + 907133923U;
780+
hash = hash * 69069U + 907133923UL;
781781
if (hash == -1)
782-
hash = 590923713U;
782+
hash = 590923713UL;
783783
so->hash = hash;
784784
return hash;
785785
}

Objects/tupleobject.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,22 +327,22 @@ tuplerepr(PyTupleObject *v)
327327
static Py_hash_t
328328
tuplehash(PyTupleObject *v)
329329
{
330-
register Py_uhash_t x;
330+
register Py_uhash_t x; /* Unsigned for defined overflow behavior. */
331331
register Py_hash_t y;
332332
register Py_ssize_t len = Py_SIZE(v);
333333
register PyObject **p;
334334
Py_uhash_t mult = _PyHASH_MULTIPLIER;
335-
x = 0x345678;
335+
x = 0x345678UL;
336336
p = v->ob_item;
337337
while (--len >= 0) {
338338
y = PyObject_Hash(*p++);
339339
if (y == -1)
340340
return -1;
341341
x = (x ^ y) * mult;
342342
/* the cast might truncate len; that doesn't change hash stability */
343-
mult += (Py_hash_t)(82520L + len + len);
343+
mult += (Py_hash_t)(82520UL + len + len);
344344
}
345-
x += 97531L;
345+
x += 97531UL;
346346
if (x == (Py_uhash_t)-1)
347347
x = -2;
348348
return x;

Objects/unicodeobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11008,7 +11008,7 @@ static Py_hash_t
1100811008
unicode_hash(PyObject *self)
1100911009
{
1101011010
Py_ssize_t len;
11011-
Py_uhash_t x;
11011+
Py_uhash_t x; /* Unsigned for defined overflow behavior. */
1101211012

1101311013
#ifdef Py_DEBUG
1101411014
assert(_Py_HashSecret_Initialized);

0 commit comments

Comments
 (0)