mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-08-28 13:34:07 +00:00
Fix ESP font hot-path stack overflow
This commit is contained in:
@@ -68,6 +68,14 @@ if(BUILD_TESTING)
|
||||
COMMAND trailmate_esp32_lvgl_sd_coredump_contract_smoke
|
||||
"${TRAIL_MATE_REPO_ROOT}")
|
||||
|
||||
add_executable(trailmate_esp32_lvgl_font_hot_path_contract_smoke
|
||||
tests/esp32_lvgl_font_hot_path_contract_smoke.cpp)
|
||||
target_compile_features(trailmate_esp32_lvgl_font_hot_path_contract_smoke
|
||||
PRIVATE cxx_std_17)
|
||||
add_test(NAME trailmate_esp32_lvgl_font_hot_path_contract_smoke
|
||||
COMMAND trailmate_esp32_lvgl_font_hot_path_contract_smoke
|
||||
"${TRAIL_MATE_REPO_ROOT}")
|
||||
|
||||
add_executable(trailmate_product_target_profile_smoke
|
||||
"${TRAIL_MATE_REPO_ROOT}/modules/product_composition/tests/test_target_profile.cpp")
|
||||
target_link_libraries(trailmate_product_target_profile_smoke
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <cassert>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::string read_file(const std::filesystem::path& path)
|
||||
{
|
||||
std::ifstream stream(path, std::ios::binary);
|
||||
assert(stream.is_open());
|
||||
std::ostringstream out;
|
||||
out << stream.rdbuf();
|
||||
return out.str();
|
||||
}
|
||||
|
||||
bool contains(const std::string& haystack, const char* needle)
|
||||
{
|
||||
return haystack.find(needle) != std::string::npos;
|
||||
}
|
||||
|
||||
bool not_contains(const std::string& haystack, const char* needle)
|
||||
{
|
||||
return !contains(haystack, needle);
|
||||
}
|
||||
|
||||
std::size_t position_of(const std::string& haystack, const char* needle)
|
||||
{
|
||||
const auto pos = haystack.find(needle);
|
||||
assert(pos != std::string::npos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
std::size_t position_of_after(const std::string& haystack,
|
||||
const char* needle,
|
||||
std::size_t offset)
|
||||
{
|
||||
const auto pos = haystack.find(needle, offset);
|
||||
assert(pos != std::string::npos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
assert(argc == 2);
|
||||
const std::filesystem::path repo_root = argv[1];
|
||||
|
||||
const std::string registry = read_file(
|
||||
repo_root / "modules/ui_shared/src/ui/i18n/resource_pack_registry.cpp");
|
||||
|
||||
assert(contains(registry, "bool s_defer_font_load_overlay_present = false;"));
|
||||
assert(contains(registry, "font_load_overlay_policy()"));
|
||||
assert(contains(registry, "Policy::Overlay"));
|
||||
assert(contains(registry, "Policy::OverlayImmediate"));
|
||||
assert(contains(registry, "font_load_overlay_policy(),"));
|
||||
|
||||
const std::size_t forced_overlay = position_of(registry, "class ScopedForcedFontLoadOverlay");
|
||||
const std::size_t defer_restore = position_of(registry, "previous_defer_present_");
|
||||
const std::size_t defer_enable = position_of(registry, "s_defer_font_load_overlay_present = true;");
|
||||
assert(forced_overlay < defer_restore);
|
||||
assert(defer_restore < defer_enable);
|
||||
|
||||
const std::size_t hot_path_guard = position_of(registry, "bool can_activate_content_supplement_for_text");
|
||||
const std::size_t hot_path_check = position_of(registry, "can_load_font_from_content_hot_path(pack)");
|
||||
const std::size_t budget_check = position_of(registry, "can_add_content_supplement(pack)");
|
||||
assert(hot_path_guard < hot_path_check);
|
||||
assert(hot_path_check < budget_check);
|
||||
|
||||
const std::size_t content_ensure = position_of(registry, "bool ensure_content_font_for_text");
|
||||
const std::size_t supplement_check = position_of(
|
||||
registry,
|
||||
"!can_activate_content_supplement_for_text(*candidate)");
|
||||
const std::size_t hot_path_reason = position_of_after(registry, "\"ui_hot_path\"", supplement_check);
|
||||
const std::size_t content_budget_reason = position_of_after(registry, "\"content_budget\"", supplement_check);
|
||||
assert(content_ensure < supplement_check);
|
||||
assert(supplement_check < hot_path_reason);
|
||||
assert(supplement_check < content_budget_reason);
|
||||
|
||||
assert(not_contains(
|
||||
registry,
|
||||
"foreground::make_snapshot(foreground::Slot::I18nFontLoad,\n"
|
||||
" foreground::Policy::OverlayImmediate"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -191,6 +191,7 @@ unsigned s_ui_helper_route_diagnostics = 0;
|
||||
unsigned s_direct_route_diagnostics = 0;
|
||||
bool s_allow_sync_external_font_activation = false;
|
||||
bool s_force_font_load_overlay = false;
|
||||
bool s_defer_font_load_overlay_present = false;
|
||||
std::uint32_t s_font_load_overlay_generation = 0;
|
||||
|
||||
std::uint32_t next_font_load_overlay_generation()
|
||||
@@ -203,6 +204,13 @@ std::uint32_t next_font_load_overlay_generation()
|
||||
return s_font_load_overlay_generation;
|
||||
}
|
||||
|
||||
::ui::widgets::foreground_operation::Policy font_load_overlay_policy()
|
||||
{
|
||||
return s_defer_font_load_overlay_present
|
||||
? ::ui::widgets::foreground_operation::Policy::Overlay
|
||||
: ::ui::widgets::foreground_operation::Policy::OverlayImmediate;
|
||||
}
|
||||
|
||||
class ScopedFontLoadOverlay
|
||||
{
|
||||
public:
|
||||
@@ -218,7 +226,7 @@ class ScopedFontLoadOverlay
|
||||
namespace foreground = ::ui::widgets::foreground_operation;
|
||||
foreground::publish(
|
||||
foreground::make_snapshot(foreground::Slot::I18nFontLoad,
|
||||
foreground::Policy::OverlayImmediate,
|
||||
font_load_overlay_policy(),
|
||||
foreground::Priority::Blocking,
|
||||
"Loading language pack...",
|
||||
pack.display_name.empty()
|
||||
@@ -330,14 +338,17 @@ class ScopedForcedFontLoadOverlay
|
||||
{
|
||||
public:
|
||||
ScopedForcedFontLoadOverlay()
|
||||
: previous_force_overlay_(s_force_font_load_overlay)
|
||||
: previous_force_overlay_(s_force_font_load_overlay),
|
||||
previous_defer_present_(s_defer_font_load_overlay_present)
|
||||
{
|
||||
s_force_font_load_overlay = true;
|
||||
s_defer_font_load_overlay_present = true;
|
||||
}
|
||||
|
||||
~ScopedForcedFontLoadOverlay()
|
||||
{
|
||||
s_force_font_load_overlay = previous_force_overlay_;
|
||||
s_defer_font_load_overlay_present = previous_defer_present_;
|
||||
}
|
||||
|
||||
ScopedForcedFontLoadOverlay(const ScopedForcedFontLoadOverlay&) = delete;
|
||||
@@ -345,6 +356,7 @@ class ScopedForcedFontLoadOverlay
|
||||
|
||||
private:
|
||||
bool previous_force_overlay_ = false;
|
||||
bool previous_defer_present_ = false;
|
||||
};
|
||||
|
||||
const char* safe_text(const char* value)
|
||||
@@ -1616,11 +1628,14 @@ bool can_activate_content_supplement_for_text(const FontPackRecord& pack)
|
||||
// Content text is data from contacts, chat, map labels, and extension pages.
|
||||
// It must not be tied to the display locale: an English UI can still need a
|
||||
// Chinese/Korean/emoji content font when those optional packs are installed.
|
||||
// The guard here is coverage + memory-profile budget, while load_font_pack()
|
||||
// still owns failure backoff so a missing/bad pack is not retried per label.
|
||||
// The guard here is hot-path safety + coverage + memory-profile budget,
|
||||
// while load_font_pack() still owns failure backoff so a missing/bad pack is
|
||||
// not retried per label.
|
||||
return pack.builtin ||
|
||||
is_font_runtime_loaded(pack) ||
|
||||
(font_pack_supports_content(pack) && can_add_content_supplement(pack));
|
||||
(can_load_font_from_content_hot_path(pack) &&
|
||||
font_pack_supports_content(pack) &&
|
||||
can_add_content_supplement(pack));
|
||||
#else
|
||||
(void)pack;
|
||||
return true;
|
||||
@@ -3331,7 +3346,9 @@ bool ensure_content_font_for_text(const char* text)
|
||||
!kAllowSynchronousContentSupplementFontLoad &&
|
||||
!can_activate_content_supplement_for_text(*candidate))
|
||||
{
|
||||
log_font_load_deferred(*candidate, "content_supplement", "content_budget");
|
||||
const char* reason =
|
||||
can_load_font_from_content_hot_path(*candidate) ? "content_budget" : "ui_hot_path";
|
||||
log_font_load_deferred(*candidate, "content_supplement", reason);
|
||||
break;
|
||||
}
|
||||
if (!ensure_font_pack_loaded(candidate))
|
||||
|
||||
Reference in New Issue
Block a user