}
/** Multiply, checking for overflow
+ *
+ * Multiplication will only occur if it would not overflow.
*
* @param[out] result of multiplication.
* @param[in] lhs First operand.
*/
bool fr_multiply(uint64_t *result, uint64_t lhs, uint64_t rhs)
{
- *result = lhs * rhs;
+ if (rhs > 0 && (UINT64_MAX / rhs) < lhs) return true;
+
+ *result = lhs * rhs; /* ubsan would flag this */
+
+ return false;
+}
+
+/** Multiply with modulo wrap
+ *
+ * Avoids multiplication overflow.
+ *
+ * @param[in] lhs First operand.
+ * @param[in] rhs Second operand.
+ * @param[in] mod Modulo.
+ * @return
+ * - Result.
+ */
+uint64_t fr_multiply_mod(uint64_t lhs, uint64_t rhs, uint64_t mod)
+{
+ uint64_t res;
+
+ lhs %= mod;
+
+ while (rhs > 0) {
+ if (rhs & 0x01) res = (res + lhs) % mod;
+
+ lhs = (lhs * 2) % mod;
+ rhs /= 2;
+ }
- return rhs > 0 && (UINT64_MAX / rhs) < lhs;
+ return res % mod;
}
/** Compares two pointers
int fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str);
bool fr_multiply(uint64_t *result, uint64_t lhs, uint64_t rhs);
+uint64_t fr_multiply_mod(uint64_t lhs, uint64_t rhs, uint64_t mod);
+
int fr_size_from_str(size_t *out, char const *str);
int8_t fr_pointer_cmp(void const *a, void const *b);
void fr_quick_sort(void const *to_sort[], int min_idx, int max_idx, fr_cmp_t cmp);
static unsigned int hash(char const * username, unsigned int tablesize)
{
- int h=1;
- while (*username) {
- h = h * 7907 + *username++;
- }
- return h%tablesize;
+ uint64_t h = 1;
+
+ while (*username) h = fr_multiply_mod(h, (7907 + *username++), tablesize);
+
+ return (unsigned int)h;
}
static void release_hash_table(struct hashtable * ht){