Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[native] Let Android know what is our reason to abort() #9314

Merged
merged 10 commits into from
Oct 14, 2024
Merged
12 changes: 8 additions & 4 deletions src/native/monodroid/debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,13 @@ Debug::start_debugging_and_profiling ()
if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_CONNECT_PROPERTY, &connect_args) > 0) {
DebuggerConnectionStatus res = start_connection (connect_args);
if (res == DebuggerConnectionStatus::Error) {
log_fatal (LOG_DEBUGGER, "Could not start a connection to the debugger with connection args '%s'.", connect_args);
Helpers::abort_application ();
Helpers::abort_application (
LOG_DEBUGGER,
Util::monodroid_strdup_printf (
"Connection to debugger failed. Args: %s",
connect_args
)
);
} else if (res == DebuggerConnectionStatus::Connected) {
/* Wait for XS to configure debugging/profiling */
gettimeofday(&wait_tv, nullptr);
Expand Down Expand Up @@ -604,8 +609,7 @@ xamarin::android::conn_thread (void *arg)
Debug *instance = static_cast<Debug*> (arg);
res = instance->handle_server_connection ();
if (res && res != 3) {
log_fatal (LOG_DEBUGGER, "Error communicating with the IDE, exiting...");
Helpers::abort_application ();
Helpers::abort_application (LOG_DEBUGGER, "Error communicating with the IDE, exiting...");
}

return nullptr;
Expand Down
97 changes: 78 additions & 19 deletions src/native/monodroid/embedded-assemblies-zip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,25 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector<uint8

log_debug (LOG_ASSEMBLY, "%s entry: %s", state.file_name, entry_name.get () == nullptr ? "unknown" : entry_name.get ());
if (!result || entry_name.empty ()) {
log_fatal (LOG_ASSEMBLY, "Failed to read Central Directory info for entry %u in APK file %s", entry_index, state.file_name);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Failed to read Central Directory info for entry %u in APK %s",
entry_index,
state.file_name
)
);
}

if (!zip_adjust_data_offset (state.file_fd, state)) {
log_fatal (LOG_ASSEMBLY, "Failed to adjust data start offset for entry %u in APK file %s", entry_index, state.file_name);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Failed to adjust data start offset for entry %u in APK %s",
entry_index,
state.file_name
)
);
}

log_debug (LOG_ASSEMBLY, " ZIP: local header offset: %u; data offset: %u; file size: %u", state.local_header_offset, state.data_offset, state.file_size);
Expand Down Expand Up @@ -61,9 +73,15 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector<uint8

// assemblies must be 16-byte or 4-byte aligned, or Bad Things happen
if (((state.data_offset & 0xf) != 0) || ((state.data_offset & 0x3) != 0)) {
log_fatal (LOG_ASSEMBLY, "Assembly '%s' is located at bad offset %lu within the .apk", entry_name.get (), state.data_offset);
log_fatal (LOG_ASSEMBLY, "You MUST run `zipalign` on %s to align it on 4 or 16 bytes ", strrchr (state.file_name, '/') + 1);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Assembly '%s' is at bad offset %lu in the APK (not aligned to 4 or 16 bytes). 'zipalign' MUST be used on %s to align it properly",
entry_name.get (),
state.data_offset,
strrchr (state.file_name, '/') + 1
)
);
}

return true;
Expand Down Expand Up @@ -161,8 +179,13 @@ inline void
EmbeddedAssemblies::map_assembly_store (dynamic_local_string<SENSIBLE_PATH_MAX> const& entry_name, ZipEntryLoadState &state) noexcept
{
if (number_of_mapped_assembly_stores > number_of_assembly_store_files) {
log_fatal (LOG_ASSEMBLY, "Too many assembly stores. Expected at most %u", number_of_assembly_store_files);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Too many assembly stores. Expected at most %u",
number_of_assembly_store_files
)
);
}

int fd;
Expand Down Expand Up @@ -192,13 +215,25 @@ EmbeddedAssemblies::map_assembly_store (dynamic_local_string<SENSIBLE_PATH_MAX>
auto header = static_cast<AssemblyStoreHeader*>(payload_start);

if (header->magic != ASSEMBLY_STORE_MAGIC) {
log_fatal (LOG_ASSEMBLY, "Assembly store '%s' is not a valid .NET for Android assembly store file", entry_name.get ());
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Assembly store '%s' is not a valid .NET for Android assembly store file",
entry_name.get ()
)
);
}

if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) {
log_fatal (LOG_ASSEMBLY, "Assembly store '%s' uses format version 0x%x, instead of the expected 0x%x", entry_name.get (), header->version, ASSEMBLY_STORE_FORMAT_VERSION);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Assembly store '%s' uses format version 0x%x, instead of the expected 0x%x",
entry_name.get (),
header->version,
ASSEMBLY_STORE_FORMAT_VERSION
)
);
}

constexpr size_t header_size = sizeof(AssemblyStoreHeader);
Expand Down Expand Up @@ -272,8 +307,13 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus
uint16_t cd_entries;

if (!zip_read_cd_info (fd, cd_offset, cd_size, cd_entries)) {
log_fatal (LOG_ASSEMBLY, "Failed to read the EOCD record from APK file %s", apk_name);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Failed to read the EOCD record from APK file %s",
apk_name
)
);
}
#ifdef DEBUG
log_info (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset);
Expand All @@ -282,8 +322,16 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus
#endif
off_t retval = ::lseek (fd, static_cast<off_t>(cd_offset), SEEK_SET);
if (retval < 0) {
log_fatal (LOG_ASSEMBLY, "Failed to seek to central directory position in the APK file %s. %s (result: %d; errno: %d)", apk_name, std::strerror (errno), retval, errno);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Failed to seek to central directory position in APK: %s. retval=%d errno=%d, File=%s",
std::strerror (errno),
retval,
errno,
apk_name
)
);
}

std::vector<uint8_t> buf (cd_size);
Expand All @@ -298,12 +346,23 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus
.local_header_offset = 0,
.data_offset = 0,
.file_size = 0,
.bundled_assemblies_slow_path = false,
.max_assembly_name_size = 0,
.max_assembly_file_name_size = 0,
};

ssize_t nread = read (fd, buf.data (), static_cast<read_count_type>(buf.size ()));
if (static_cast<size_t>(nread) != cd_size) {
log_fatal (LOG_ASSEMBLY, "Failed to read Central Directory from the APK archive %s. %s (nread: %d; errno: %d)", apk_name, std::strerror (errno), nread, errno);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Failed to read Central Directory from APK: %s. nread=%d errno=%d File=%s",
std::strerror (errno),
nread,
errno,
apk_name
)
);
}

if (application_config.have_assembly_store) {
Expand Down
88 changes: 67 additions & 21 deletions src/native/monodroid/embedded-assemblies.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,16 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb
auto header = reinterpret_cast<const CompressedAssemblyHeader*>(data);
if (header->magic == COMPRESSED_DATA_MAGIC) {
if (compressed_assemblies.descriptors == nullptr) [[unlikely]] {
log_fatal (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined");
Helpers::abort_application ();
Helpers::abort_application (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined");
}
if (header->descriptor_index >= compressed_assemblies.count) [[unlikely]] {
log_fatal (LOG_ASSEMBLY, "Invalid compressed assembly descriptor index %u", header->descriptor_index);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Invalid compressed assembly descriptor index %u",
header->descriptor_index
)
);
}

CompressedAssemblyDescriptor &cad = compressed_assemblies.descriptors[header->descriptor_index];
Expand All @@ -105,14 +109,26 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb
}

if (cad.data == nullptr) [[unlikely]] {
log_fatal (LOG_ASSEMBLY, "Invalid compressed assembly descriptor at %u: no data", header->descriptor_index);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Invalid compressed assembly descriptor at %u: no data",
header->descriptor_index
)
);
}

if (header->uncompressed_length != cad.uncompressed_file_size) {
if (header->uncompressed_length > cad.uncompressed_file_size) {
log_fatal (LOG_ASSEMBLY, "Compressed assembly '%s' is larger than when the application was built (expected at most %u, got %u). Assemblies don't grow just like that!", name, cad.uncompressed_file_size, header->uncompressed_length);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Compressed assembly '%s' is larger than when the application was built (expected at most %u, got %u). Assemblies don't grow just like that!",
name,
cad.uncompressed_file_size,
header->uncompressed_length
)
);
} else {
log_debug (LOG_ASSEMBLY, "Compressed assembly '%s' is smaller than when the application was built. Adjusting accordingly.", name);
}
Expand All @@ -123,13 +139,26 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb
int ret = LZ4_decompress_safe (data_start, reinterpret_cast<char*>(cad.data), static_cast<int>(assembly_data_size), static_cast<int>(cad.uncompressed_file_size));

if (ret < 0) {
log_fatal (LOG_ASSEMBLY, "Decompression of assembly %s failed with code %d", name, ret);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Decompression of assembly %s failed with code %d",
name,
ret
)
);
}

if (static_cast<uint64_t>(ret) != cad.uncompressed_file_size) {
log_debug (LOG_ASSEMBLY, "Decompression of assembly %s yielded a different size (expected %lu, got %u)", name, cad.uncompressed_file_size, static_cast<uint32_t>(ret));
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Decompression of assembly %s yielded a different size (expected %lu, got %u)",
name,
cad.uncompressed_file_size,
static_cast<uint32_t>(ret)
)
);
}
cad.loaded = true;
}
Expand Down Expand Up @@ -366,8 +395,14 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string<SENSI
}

if (hash_entry->descriptor_index >= assembly_store.assembly_count) {
log_fatal (LOG_ASSEMBLY, "Invalid assembly descriptor index %u, exceeds the maximum value of %u", hash_entry->descriptor_index, assembly_store.assembly_count - 1);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Invalid assembly descriptor index %u, exceeds the maximum value of %u",
hash_entry->descriptor_index,
assembly_store.assembly_count - 1
)
);
}

AssemblyStoreEntryDescriptor &store_entry = assembly_store.assemblies[hash_entry->descriptor_index];
Expand Down Expand Up @@ -499,8 +534,7 @@ EmbeddedAssemblies::binary_search (const Key *key, const Entry *base, size_t nme

// This is a coding error on our part, crash!
if (base == nullptr) {
log_fatal (LOG_ASSEMBLY, "Map address not passed to binary_search");
Helpers::abort_application ();
Helpers::abort_application (LOG_ASSEMBLY, "Map address not passed to binary_search");
}

[[maybe_unused]]
Expand Down Expand Up @@ -855,8 +889,15 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons
mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast<off_t>(offsetPage));

if (mmap_info.area == MAP_FAILED) {
log_fatal (LOG_DEFAULT, "Could not `mmap` apk fd %d entry `%s`: %s", fd, filename, strerror (errno));
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Could not mmap APK fd %d: %s; File=%s",
fd,
strerror (errno),
filename
)
);
}

mmap_info.size = offsetSize;
Expand All @@ -876,10 +917,15 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro
int fd;

if ((fd = open (apk, O_RDONLY)) < 0) {
log_error (LOG_DEFAULT, "ERROR: Unable to load application package %s.", apk);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"ERROR: Unable to load application package %s.",
apk
)
);
}
log_info (LOG_ASSEMBLY, "APK %s FD: %d", apk, fd);
log_debug (LOG_ASSEMBLY, "APK %s FD: %d", apk, fd);

zip_load_entries (fd, apk, should_register);
}
Expand Down
10 changes: 8 additions & 2 deletions src/native/monodroid/mono-image-loader.hh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "xxhash.hh"
#include "search.hh"
#include "strings.hh"
#include "util.hh"

#if defined (RELEASE)
#define USE_CACHE 1
Expand Down Expand Up @@ -116,8 +117,13 @@ namespace xamarin::android::internal {
#if defined (USE_CACHE)
ssize_t index = find_index (hash);
if (index < 0) {
log_fatal (LOG_ASSEMBLY, "Failed to look up image index for hash 0x%zx", hash);
Helpers::abort_application ();
Helpers::abort_application (
LOG_ASSEMBLY,
Util::monodroid_strdup_printf (
"Failed to look up image index for hash 0x%zx",
hash
)
);
}

// We don't need to worry about locking here. Even if we're overwriting an entry just set by another
Expand Down
2 changes: 1 addition & 1 deletion src/native/monodroid/mono-log-adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ MonodroidRuntime::mono_log_handler (const char *log_domain, const char *log_leve

__android_log_write (prio, log_domain, message);
if (fatal) {
Helpers::abort_application ();
Helpers::abort_application (message);
}
}

Expand Down
Loading
Loading