Skip to content

Commit 4e33337

Browse files
committed
Avoid all compiler optimization on embedded apphost hash
We assume that there is a single copy of the apphost hash in the apphost binary. And that it hasn't been modified by the compiler. However, the compiler can optimize the hash multiple ways, including re-ordering elements of the hash or duplicating the contents of the hash. This can currently happen under certain compiler versions and optimization flags. Try and avoid that by marking the hash as a volatile string and implementing comparisons/copying/initialization that respects that. Fixes: dotnet#109611
1 parent 016d356 commit 4e33337

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

src/native/corehost/corehost.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@
4040
#define EMBED_HASH_LO_PART_UTF8 "74e592c2fa383d4a3960714caef0c4f2"
4141
#define EMBED_HASH_FULL_UTF8 (EMBED_HASH_HI_PART_UTF8 EMBED_HASH_LO_PART_UTF8) // NUL terminated
4242

43+
void to_non_volatile(volatile const char* cstr, char* output, size_t length)
44+
{
45+
for (size_t i = 0; i < length; i++)
46+
{
47+
output[i] = cstr[i];
48+
}
49+
}
50+
51+
bool compare_memory_nooptimization(volatile const char* a, volatile const char* b, size_t length)
52+
{
53+
for (size_t i = 0; i < length; i++)
54+
{
55+
if (*a++ != *b++)
56+
return false;
57+
}
58+
return true;
59+
}
60+
4361
bool is_exe_enabled_for_execution(pal::string_t* app_dll)
4462
{
4563
constexpr int EMBED_SZ = sizeof(EMBED_HASH_FULL_UTF8) / sizeof(EMBED_HASH_FULL_UTF8[0]);
@@ -48,18 +66,21 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll)
4866
// Contains the EMBED_HASH_FULL_UTF8 value at compile time or the managed DLL name replaced by "dotnet build".
4967
// Must not be 'const' because std::string(&embed[0]) below would bind to a const string ctor plus length
5068
// where length is determined at compile time (=64) instead of the actual length of the string at runtime.
51-
static char embed[EMBED_MAX] = EMBED_HASH_FULL_UTF8; // series of NULs followed by embed hash string
69+
volatile static char embed[EMBED_MAX] = EMBED_HASH_FULL_UTF8; // series of NULs followed by embed hash string
5270

5371
static const char hi_part[] = EMBED_HASH_HI_PART_UTF8;
5472
static const char lo_part[] = EMBED_HASH_LO_PART_UTF8;
5573

56-
if (!pal::clr_palstring(embed, app_dll))
74+
char working_copy_embed[EMBED_MAX];
75+
to_non_volatile(embed, working_copy_embed, EMBED_MAX);
76+
77+
if (!pal::clr_palstring(&working_copy_embed[0], app_dll))
5778
{
5879
trace::error(_X("The managed DLL bound to this executable could not be retrieved from the executable image."));
5980
return false;
6081
}
6182

62-
std::string binding(&embed[0]);
83+
std::string binding(&working_copy_embed[0]);
6384

6485
// Check if the path exceeds the max allowed size
6586
if (binding.size() > EMBED_MAX - 1) // -1 for null terminator
@@ -74,8 +95,8 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll)
7495
size_t hi_len = (sizeof(hi_part) / sizeof(hi_part[0])) - 1;
7596
size_t lo_len = (sizeof(lo_part) / sizeof(lo_part[0])) - 1;
7697
if (binding.size() >= (hi_len + lo_len)
77-
&& binding.compare(0, hi_len, &hi_part[0]) == 0
78-
&& binding.compare(hi_len, lo_len, &lo_part[0]) == 0)
98+
&& compare_memory_nooptimization(binding.c_str(), hi_part, hi_len)
99+
&& compare_memory_nooptimization(binding.substr(hi_len).c_str(), lo_part, lo_len))
79100
{
80101
trace::error(_X("This executable is not bound to a managed DLL to execute. The binding value is: '%s'"), app_dll->c_str());
81102
return false;

0 commit comments

Comments
 (0)