From 43be9fa0c8024abab0ce684ed30a8c9c6234558f Mon Sep 17 00:00:00 2001 From: Jan Haller Date: Sun, 24 Sep 2023 15:58:28 +0200 Subject: [PATCH] Fix platform-dependent hashing for char* and wchar_t* Since char/wchar_t can be either signed or unsigned, its conversion to uint32_t leads to different values depending on platform. In particular, the same string represented as char* (Latin-1; StringName direct construction) or uint32_t (UTF-8; constructed via String) previously resulted in different hashes. --- core/string/ustring.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index f6a17cf1a7..5a42a3af12 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -2763,12 +2763,13 @@ double String::to_float() const { } uint32_t String::hash(const char *p_cstr) { + // static_cast: avoid negative values on platforms where char is signed. uint32_t hashv = 5381; - uint32_t c = *p_cstr++; + uint32_t c = static_cast(*p_cstr++); while (c) { hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */ - c = *p_cstr++; + c = static_cast(*p_cstr++); } return hashv; @@ -2777,28 +2778,35 @@ uint32_t String::hash(const char *p_cstr) { uint32_t String::hash(const char *p_cstr, int p_len) { uint32_t hashv = 5381; for (int i = 0; i < p_len; i++) { - hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */ + // static_cast: avoid negative values on platforms where char is signed. + hashv = ((hashv << 5) + hashv) + static_cast(p_cstr[i]); /* hash * 33 + c */ } return hashv; } uint32_t String::hash(const wchar_t *p_cstr, int p_len) { + // Avoid negative values on platforms where wchar_t is signed. Account for different sizes. + using wide_unsigned = std::conditional::type; + uint32_t hashv = 5381; for (int i = 0; i < p_len; i++) { - hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */ + hashv = ((hashv << 5) + hashv) + static_cast(p_cstr[i]); /* hash * 33 + c */ } return hashv; } uint32_t String::hash(const wchar_t *p_cstr) { + // Avoid negative values on platforms where wchar_t is signed. Account for different sizes. + using wide_unsigned = std::conditional::type; + uint32_t hashv = 5381; - uint32_t c = *p_cstr++; + uint32_t c = static_cast(*p_cstr++); while (c) { hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */ - c = *p_cstr++; + c = static_cast(*p_cstr++); } return hashv;