Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/mono/wasi/build/WasiApp.CoreCLR.targets
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@
SourceFiles="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat"
DestinationFolder="$(WasmAppDir)managed"
SkipUnchangedFiles="true" />
<!-- The wasihost corehost reads the app's runtimeconfig properties from runtimeconfig.bin
next to the entry assembly and passes them to the runtime. -->
<Copy Condition="'$(_ParsedRuntimeConfigFilePath)' != '' and Exists('$(_ParsedRuntimeConfigFilePath)')"
SourceFiles="$(_ParsedRuntimeConfigFilePath)"
DestinationFolder="$(WasmAppDir)managed"
SkipUnchangedFiles="true" />
</Target>

<!-- ============================ Per-app wasihost link ============================ -->
Expand Down
111 changes: 111 additions & 0 deletions src/native/corehost/wasihost/wasihost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// real wasi:cli/run main() instead of a JS driver.
// See https://github.com/dotnet/runtime/issues/130129.

#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstring>
Expand Down Expand Up @@ -158,6 +159,110 @@ static string_t build_tpa(const string_t& core_root, const string_t& core_librar
return tpa_list.str();
}

// ECMA-335 compressed unsigned integer (II.23.2), as written by BlobBuilder.WriteCompressedInteger.
static bool read_compressed_uint(const uint8_t*& cur, const uint8_t* end, uint32_t& value)
{
if (cur >= end)
return false;

uint8_t b = cur[0];
if ((b & 0x80) == 0)
{
value = b;
cur += 1;
return true;
}

if ((b & 0xC0) == 0x80)
{
if (end - cur < 2)
return false;

value = (static_cast<uint32_t>(b & 0x3F) << 8) | cur[1];
cur += 2;
return true;
}

if ((b & 0xE0) == 0xC0)
{
if (end - cur < 4)
return false;

value = (static_cast<uint32_t>(b & 0x1F) << 24) | (static_cast<uint32_t>(cur[1]) << 16) | (static_cast<uint32_t>(cur[2]) << 8) | cur[3];
cur += 4;
return true;
}

return false;
}

// Length-prefixed UTF-8 string, as written by BlobBuilder.WriteSerializedString.
static bool read_serialized_string(const uint8_t*& cur, const uint8_t* end, std::string& value)
{
uint32_t len;
if (!read_compressed_uint(cur, end, len) || static_cast<size_t>(end - cur) < len)
return false;

value.assign(reinterpret_cast<const char*>(cur), len);
cur += len;
return true;
}

// Appends the app's runtimeconfig configProperties (feature switches, RuntimeHostConfigurationOption
// items, ...) to the init properties. Reads the runtimeconfig.bin that RuntimeConfigParserTask writes
// (the same file Mono's WASI driver consumes): a compressed count followed by that many key/value
// serialized strings. Properties already set by the host take precedence. A missing file is not an
// error.
static bool add_runtimeconfig_properties(const string_t& path)
{
FILE* file = std::fopen(path.c_str(), "rb");
if (file == nullptr)
return true;

std::vector<uint8_t> data;
uint8_t buffer[4096];
size_t read;
while ((read = std::fread(buffer, 1, sizeof(buffer), file)) > 0)
data.insert(data.end(), buffer, buffer + read);

bool read_error = std::ferror(file) != 0;
std::fclose(file);

const uint8_t* cur = data.data();
const uint8_t* end = cur + data.size();
uint32_t count = 0;
bool valid = !read_error && read_compressed_uint(cur, end, count);
std::vector<std::string> keys;
std::vector<std::string> values;
for (uint32_t i = 0; valid && i < count; ++i)
{
std::string key;
std::string value;
valid = read_serialized_string(cur, end, key) && read_serialized_string(cur, end, value);
keys.push_back(std::move(key));
values.push_back(std::move(value));
}

if (!valid)
{
std::fprintf(stderr, "Failed to read runtime configuration from '%s'\n", path.c_str());
return false;
}

size_t host_property_count = s_property_keys.size();
for (size_t i = 0; i < keys.size(); ++i)
{
auto host_keys_end = s_property_keys.begin() + host_property_count;
if (std::find(s_property_keys.begin(), host_keys_end, keys[i]) != host_keys_end)
continue;

s_property_keys.push_back(std::move(keys[i]));
s_property_values.push_back(std::move(values[i]));
}

return true;
}

static size_t HOST_CONTRACT_CALLTYPE get_runtime_property(
const char* key,
/*out*/ char* value_buffer,
Expand Down Expand Up @@ -248,6 +353,12 @@ int main(int argc, char* argv[])
s_property_values.push_back(ss.str());
}

// The app bundle places runtimeconfig.bin next to the entry assembly.
string_t runtimeconfig_path = app_path;
runtimeconfig_path.append(W("runtimeconfig.bin"));
if (!add_runtimeconfig_properties(runtimeconfig_path))
return -1;

std::vector<const char*> property_keys;
std::vector<const char*> property_values;
for (const std::string& key : s_property_keys)
Expand Down
Loading