-
Notifications
You must be signed in to change notification settings - Fork 537
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
Prevent overlapped decompression of embedded assemblies #7732
Changes from 3 commits
9d2740d
171c170
8d11a8d
3b1c93b
232d8da
efc88b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ | |
#include "mono-image-loader.hh" | ||
#include "xamarin-app.hh" | ||
#include "cpp-util.hh" | ||
#include "monodroid-glue-internal.hh" | ||
#include "startup-aware-lock.hh" | ||
#include "timing-internal.hh" | ||
#include "search.hh" | ||
|
@@ -73,6 +74,13 @@ void EmbeddedAssemblies::set_assemblies_prefix (const char *prefix) | |
assemblies_prefix_override = prefix != nullptr ? utils.strdup_new (prefix) : nullptr; | ||
} | ||
|
||
force_inline void | ||
EmbeddedAssemblies::set_assembly_data_and_size (uint8_t* source_assembly_data, uint32_t source_assembly_data_size, uint8_t*& dest_assembly_data, uint32_t& dest_assembly_data_size) noexcept | ||
{ | ||
dest_assembly_data = source_assembly_data; | ||
dest_assembly_data_size = source_assembly_data_size; | ||
} | ||
|
||
force_inline void | ||
EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[maybe_unused]] const char *name, uint8_t*& assembly_data, uint32_t& assembly_data_size) noexcept | ||
{ | ||
|
@@ -81,31 +89,32 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb | |
if (header->magic == COMPRESSED_DATA_MAGIC) { | ||
if (XA_UNLIKELY (compressed_assemblies.descriptors == nullptr)) { | ||
log_fatal (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined"); | ||
exit (FATAL_EXIT_MISSING_ASSEMBLY); | ||
abort (); | ||
} | ||
if (XA_UNLIKELY (header->descriptor_index >= compressed_assemblies.count)) { | ||
log_fatal (LOG_ASSEMBLY, "Invalid compressed assembly descriptor index %u", header->descriptor_index); | ||
exit (FATAL_EXIT_MISSING_ASSEMBLY); | ||
abort (); | ||
} | ||
|
||
CompressedAssemblyDescriptor &cad = compressed_assemblies.descriptors[header->descriptor_index]; | ||
assembly_data_size = data_size - sizeof(CompressedAssemblyHeader); | ||
if (!cad.loaded) { | ||
if (XA_UNLIKELY (cad.data == nullptr)) { | ||
log_fatal (LOG_ASSEMBLY, "Invalid compressed assembly descriptor at %u: no data", header->descriptor_index); | ||
exit (FATAL_EXIT_MISSING_ASSEMBLY); | ||
StartupAwareLock decompress_lock (assembly_decompress_mutex); | ||
|
||
if (cad.loaded) { | ||
set_assembly_data_and_size (reinterpret_cast<uint8_t*>(cad.data), cad.uncompressed_file_size, assembly_data, assembly_data_size); | ||
return; | ||
} | ||
dellis1972 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
bool log_timing = FastTiming::enabled () && !FastTiming::is_bare_mode (); | ||
size_t decompress_time_index; | ||
if (XA_UNLIKELY (log_timing)) { | ||
decompress_time_index = internal_timing->start_event (TimingEventKind::AssemblyDecompression); | ||
if (XA_UNLIKELY (cad.data == nullptr)) { | ||
log_fatal (LOG_ASSEMBLY, "Invalid compressed assembly descriptor at %u: no data", header->descriptor_index); | ||
abort (); | ||
} | ||
|
||
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); | ||
exit (FATAL_EXIT_MISSING_ASSEMBLY); | ||
abort (); | ||
} else { | ||
log_debug (LOG_ASSEMBLY, "Compressed assembly '%s' is smaller than when the application was built. Adjusting accordingly.", name); | ||
} | ||
|
@@ -115,29 +124,23 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb | |
const char *data_start = reinterpret_cast<const char*>(data + sizeof(CompressedAssemblyHeader)); | ||
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 (XA_UNLIKELY (log_timing)) { | ||
internal_timing->end_event (decompress_time_index, true /* uses_more_info */); | ||
internal_timing->add_more_info (decompress_time_index, name); | ||
Comment on lines
-119
to
-120
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this timing message not that helpful? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, I used it initially to see how much decompression itself costs us, but right now it's just wasted CPU cycles. |
||
} | ||
|
||
if (ret < 0) { | ||
log_fatal (LOG_ASSEMBLY, "Decompression of assembly %s failed with code %d", name, ret); | ||
exit (FATAL_EXIT_MISSING_ASSEMBLY); | ||
abort (); | ||
} | ||
|
||
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)); | ||
exit (FATAL_EXIT_MISSING_ASSEMBLY); | ||
abort (); | ||
} | ||
cad.loaded = true; | ||
} | ||
assembly_data = reinterpret_cast<uint8_t*>(cad.data); | ||
assembly_data_size = cad.uncompressed_file_size; | ||
|
||
set_assembly_data_and_size (reinterpret_cast<uint8_t*>(cad.data), cad.uncompressed_file_size, assembly_data, assembly_data_size); | ||
} else | ||
#endif | ||
{ | ||
assembly_data = data; | ||
assembly_data_size = data_size; | ||
set_assembly_data_and_size (data, data_size, assembly_data, assembly_data_size); | ||
} | ||
} | ||
|
||
|
@@ -357,9 +360,6 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string<SENSI | |
len -= sizeof(SharedConstants::DLL_EXTENSION) - 1; | ||
} | ||
|
||
std::string clipped_name; | ||
clipped_name.assign (name.get (), len); | ||
|
||
hash_t name_hash = xxhash::hash (name.get (), len); | ||
log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '%s' (hash 0x%zx)", name.get (), name_hash); | ||
|
||
|
@@ -411,14 +411,15 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string<SENSI | |
|
||
log_debug ( | ||
LOG_ASSEMBLY, | ||
"Mapped: image_data == %p; debug_info_data == %p; config_data == %p; descriptor == %p; data size == %u; debug data size == %u; config data size == %u", | ||
"Mapped: image_data == %p; debug_info_data == %p; config_data == %p; descriptor == %p; data size == %u; debug data size == %u; config data size == %u; name == '%s'", | ||
assembly_runtime_info.image_data, | ||
assembly_runtime_info.debug_info_data, | ||
assembly_runtime_info.config_data, | ||
assembly_runtime_info.descriptor, | ||
assembly_runtime_info.descriptor->data_size, | ||
assembly_runtime_info.descriptor->debug_data_size, | ||
assembly_runtime_info.descriptor->config_data_size | ||
assembly_runtime_info.descriptor->config_data_size, | ||
name.get () | ||
); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why
abort()
and notexit()
? I forget whatabort()
does on Android…There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exit()
causes the application to restart,abort()
kills it with a nativeSIGABRT
stack traceThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a lot of places that users complain about a "white screen", and it ended up their app was crashing and restarting.
Should we audit all of the
exit()
calls?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should, I've been meaning to do it for quite a while now. I'll open a separate PR for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR #7734 opened