From f9677bb92c416cb4944b386d7ff21eb56e783e9a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 4 May 2016 20:56:04 +0200 Subject: [PATCH] src: don't use locale-sensitive strcasecmp() strcasecmp() is affected by the current locale as configured through e.g. the LC_ALL environment variable and the setlocale() libc function. It can result in unpredictable results across systems so replace it with a function that isn't susceptible to that. PR-URL: https://github.com/nodejs/node/pull/6582 Reviewed-By: Anna Henningsen Reviewed-By: Fedor Indutny Reviewed-By: James M Snell --- src/node.cc | 27 +++++++++++++-------------- src/node_crypto.cc | 6 +----- src/util-inl.h | 12 ++++++++++++ src/util.h | 6 ++++++ test/cctest/util.cc | 18 ++++++++++++++++++ 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/node.cc b/src/node.cc index 12219b026d63b7..9be6fa5c507196 100644 --- a/src/node.cc +++ b/src/node.cc @@ -69,7 +69,6 @@ #if defined(_MSC_VER) #include #include -#define strcasecmp _stricmp #define getpid GetCurrentProcessId #define umask _umask typedef int mode_t; @@ -1350,35 +1349,35 @@ enum encoding ParseEncoding(const char* encoding, break; } - if (strcasecmp(encoding, "utf8") == 0) { + if (StringEqualNoCase(encoding, "utf8")) { return UTF8; - } else if (strcasecmp(encoding, "utf-8") == 0) { + } else if (StringEqualNoCase(encoding, "utf-8")) { return UTF8; - } else if (strcasecmp(encoding, "ascii") == 0) { + } else if (StringEqualNoCase(encoding, "ascii")) { return ASCII; - } else if (strcasecmp(encoding, "base64") == 0) { + } else if (StringEqualNoCase(encoding, "base64")) { return BASE64; - } else if (strcasecmp(encoding, "ucs2") == 0) { + } else if (StringEqualNoCase(encoding, "ucs2")) { return UCS2; - } else if (strcasecmp(encoding, "ucs-2") == 0) { + } else if (StringEqualNoCase(encoding, "ucs-2")) { return UCS2; - } else if (strcasecmp(encoding, "utf16le") == 0) { + } else if (StringEqualNoCase(encoding, "utf16le")) { return UCS2; - } else if (strcasecmp(encoding, "utf-16le") == 0) { + } else if (StringEqualNoCase(encoding, "utf-16le")) { return UCS2; - } else if (strcasecmp(encoding, "binary") == 0) { + } else if (StringEqualNoCase(encoding, "binary")) { return BINARY; - } else if (strcasecmp(encoding, "buffer") == 0) { + } else if (StringEqualNoCase(encoding, "buffer")) { return BUFFER; - } else if (strcasecmp(encoding, "hex") == 0) { + } else if (StringEqualNoCase(encoding, "hex")) { return HEX; - } else if (strcasecmp(encoding, "raw") == 0) { + } else if (StringEqualNoCase(encoding, "raw") == 0) { if (!no_deprecation) { fprintf(stderr, "'raw' (array of integers) has been removed. " "Use 'binary'.\n"); } return BINARY; - } else if (strcasecmp(encoding, "raws") == 0) { + } else if (StringEqualNoCase(encoding, "raws") == 0) { if (!no_deprecation) { fprintf(stderr, "'raws' encoding has been renamed to 'binary'. " "Please update your code.\n"); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 21e4d33cab9316..2d508d2cc3d527 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -24,10 +24,6 @@ #include #include -#if defined(_MSC_VER) -#define strcasecmp _stricmp -#endif - #if OPENSSL_VERSION_NUMBER >= 0x10000000L #define OPENSSL_CONST const #else @@ -4232,7 +4228,7 @@ void DiffieHellman::DiffieHellmanGroup( for (size_t i = 0; i < arraysize(modp_groups); ++i) { const modp_group* it = modp_groups + i; - if (strcasecmp(*group_name, it->name) != 0) + if (!StringEqualNoCase(*group_name, it->name)) continue; initialized = diffieHellman->Init(it->prime, diff --git a/src/util-inl.h b/src/util-inl.h index 69dc5b2a61a1a9..7051659a5e0e6a 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -203,7 +203,19 @@ void SwapBytes(uint16_t* dst, const uint16_t* src, size_t buflen) { dst[i] = (src[i] << 8) | (src[i] >> 8); } +char ToLower(char c) { + return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; +} +bool StringEqualNoCase(const char* a, const char* b) { + do { + if (*a == '\0') + return *b == '\0'; + if (*b == '\0') + return *a == '\0'; + } while (ToLower(*a++) == ToLower(*b++)); + return false; +} } // namespace node diff --git a/src/util.h b/src/util.h index 7b2bc0f1a270ba..671b98dd25b191 100644 --- a/src/util.h +++ b/src/util.h @@ -178,6 +178,12 @@ inline TypeName* Unwrap(v8::Local object); inline void SwapBytes(uint16_t* dst, const uint16_t* src, size_t buflen); +// tolower() is locale-sensitive. Use ToLower() instead. +inline char ToLower(char c); + +// strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead. +inline bool StringEqualNoCase(const char* a, const char* b); + class Utf8Value { public: explicit Utf8Value(v8::Isolate* isolate, v8::Local value); diff --git a/test/cctest/util.cc b/test/cctest/util.cc index fe966d9b34073c..37133aca562b72 100644 --- a/test/cctest/util.cc +++ b/test/cctest/util.cc @@ -56,3 +56,21 @@ TEST(UtilTest, ListHead) { EXPECT_TRUE(list.IsEmpty()); EXPECT_FALSE(list.begin() != list.end()); } + +TEST(UtilTest, StringEqualNoCase) { + using node::StringEqualNoCase; + EXPECT_FALSE(StringEqualNoCase("a", "b")); + EXPECT_TRUE(StringEqualNoCase("", "")); + EXPECT_TRUE(StringEqualNoCase("equal", "equal")); + EXPECT_TRUE(StringEqualNoCase("equal", "EQUAL")); + EXPECT_TRUE(StringEqualNoCase("EQUAL", "EQUAL")); + EXPECT_FALSE(StringEqualNoCase("equal", "equals")); + EXPECT_FALSE(StringEqualNoCase("equals", "equal")); +} + +TEST(UtilTest, ToLower) { + using node::ToLower; + EXPECT_EQ('0', ToLower('0')); + EXPECT_EQ('a', ToLower('a')); + EXPECT_EQ('a', ToLower('A')); +}