strings.h: Avoid overflows in the string hash functions

On 2's compliment machines abs(INT_MIN) behavior is undefined and
results in a negative value still being returnd.  This results in
negative hash codes that can result in crashes.

ASTERISK-26528 #close

Change-Id: Idff550145ca2133792a61a2e212b4a3e82c6517b
This commit is contained in:
Torrey Searle
2017-04-07 15:58:23 +02:00
committed by Torrey Searle
parent 2b8dbc9e00
commit 7901225261

View File

@@ -26,6 +26,7 @@
/* #define DEBUG_OPAQUE */ /* #define DEBUG_OPAQUE */
#include <ctype.h> #include <ctype.h>
#include <limits.h>
#include "asterisk/utils.h" #include "asterisk/utils.h"
#include "asterisk/threadstorage.h" #include "asterisk/threadstorage.h"
@@ -1173,6 +1174,19 @@ char *ast_tech_to_upper(char *dev_str),
} }
) )
/*!
* \brief Restrict hash value range
*
* \details
* Hash values used all over asterisk are expected to be non-negative
* (signed) int values. This function restricts an unsigned int hash
* value to the positive half of the (signed) int values.
*/
static force_inline int attribute_pure ast_str_hash_restrict(unsigned int hash)
{
return (int) (hash & (unsigned int) INT_MAX);
}
/*! /*!
* \brief Compute a hash value on a string * \brief Compute a hash value on a string
* *
@@ -1183,20 +1197,21 @@ char *ast_tech_to_upper(char *dev_str),
*/ */
static force_inline int attribute_pure ast_str_hash(const char *str) static force_inline int attribute_pure ast_str_hash(const char *str)
{ {
int hash = 5381; unsigned int hash = 5381;
while (*str) while (*str) {
hash = hash * 33 ^ *str++; hash = hash * 33 ^ (unsigned char) *str++;
}
return abs(hash); return ast_str_hash_restrict(hash);
} }
/*! /*!
* \brief Compute a hash value on a string * \brief Compute a hash value on a string
* *
* \param[in] str The string to add to the hash * \param[in] str The string to add to the hash
* \param[in] hash The hash value to add to * \param[in] seed The hash value to start with
* *
* \details * \details
* This version of the function is for when you need to compute a * This version of the function is for when you need to compute a
* string hash of more than one string. * string hash of more than one string.
@@ -1206,12 +1221,15 @@ static force_inline int attribute_pure ast_str_hash(const char *str)
* *
* \sa http://www.cse.yorku.ca/~oz/hash.html * \sa http://www.cse.yorku.ca/~oz/hash.html
*/ */
static force_inline int ast_str_hash_add(const char *str, int hash) static force_inline int ast_str_hash_add(const char *str, int seed)
{ {
while (*str) unsigned int hash = (unsigned int) seed;
hash = hash * 33 ^ *str++;
return abs(hash); while (*str) {
hash = hash * 33 ^ (unsigned char) *str++;
}
return ast_str_hash_restrict(hash);
} }
/*! /*!
@@ -1223,13 +1241,13 @@ static force_inline int ast_str_hash_add(const char *str, int hash)
*/ */
static force_inline int attribute_pure ast_str_case_hash(const char *str) static force_inline int attribute_pure ast_str_case_hash(const char *str)
{ {
int hash = 5381; unsigned int hash = 5381;
while (*str) { while (*str) {
hash = hash * 33 ^ tolower(*str++); hash = hash * 33 ^ (unsigned char) tolower(*str++);
} }
return abs(hash); return ast_str_hash_restrict(hash);
} }
/*! /*!