diff --git a/src/native/corehost/corehost.cpp b/src/native/corehost/corehost.cpp index 6de7acfbd08576..54eb128cb486bb 100644 --- a/src/native/corehost/corehost.cpp +++ b/src/native/corehost/corehost.cpp @@ -40,14 +40,27 @@ #define EMBED_HASH_LO_PART_UTF8 "74e592c2fa383d4a3960714caef0c4f2" #define EMBED_HASH_FULL_UTF8 (EMBED_HASH_HI_PART_UTF8 EMBED_HASH_LO_PART_UTF8) // NUL terminated +// This avoids compiler optimization which cause EMBED_HASH_HI_PART_UTF8 EMBED_HASH_LO_PART_UTF8 +// to be placed adjacent causing them to match EMBED_HASH_FULL_UTF8 when searched for replacing. +// See https://github.com/dotnet/runtime/issues/109611 for more details. +static bool compare_memory_nooptimization(volatile const char* a, volatile const char* b, size_t length) +{ + for (size_t i = 0; i < length; i++) + { + if (*a++ != *b++) + return false; + } + return true; +} + bool is_exe_enabled_for_execution(pal::string_t* app_dll) { constexpr int EMBED_SZ = sizeof(EMBED_HASH_FULL_UTF8) / sizeof(EMBED_HASH_FULL_UTF8[0]); constexpr int EMBED_MAX = (EMBED_SZ > 1025 ? EMBED_SZ : 1025); // 1024 DLL name length, 1 NUL // Contains the EMBED_HASH_FULL_UTF8 value at compile time or the managed DLL name replaced by "dotnet build". - // Must not be 'const' because std::string(&embed[0]) below would bind to a const string ctor plus length - // where length is determined at compile time (=64) instead of the actual length of the string at runtime. + // Must not be 'const' because strlen below could be determined at compile time (=64) instead of the actual + // length of the string at runtime. static char embed[EMBED_MAX] = EMBED_HASH_FULL_UTF8; // series of NULs followed by embed hash string static const char hi_part[] = EMBED_HASH_HI_PART_UTF8; @@ -59,10 +72,10 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll) return false; } - std::string binding(&embed[0]); + size_t binding_len = strlen(&embed[0]); // Check if the path exceeds the max allowed size - if (binding.size() > EMBED_MAX - 1) // -1 for null terminator + if (binding_len > EMBED_MAX - 1) // -1 for null terminator { trace::error(_X("The managed DLL bound to this executable is longer than the max allowed length (%d)"), EMBED_MAX - 1); return false; @@ -73,9 +86,9 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll) // So use two parts of the string that will be unaffected by the edit. size_t hi_len = (sizeof(hi_part) / sizeof(hi_part[0])) - 1; size_t lo_len = (sizeof(lo_part) / sizeof(lo_part[0])) - 1; - if (binding.size() >= (hi_len + lo_len) - && binding.compare(0, hi_len, &hi_part[0]) == 0 - && binding.compare(hi_len, lo_len, &lo_part[0]) == 0) + if (binding_len >= (hi_len + lo_len) + && compare_memory_nooptimization(&embed[0], hi_part, hi_len) + && compare_memory_nooptimization(&embed[hi_len], lo_part, lo_len)) { trace::error(_X("This executable is not bound to a managed DLL to execute. The binding value is: '%s'"), app_dll->c_str()); return false;