Changeset - r28584:d5de6992fa2a
[Not reviewed]
master
0 5 0
Peter Nelson - 3 months ago 2024-01-27 20:13:42
peter1138@openttd.org
Fix: Memory leak in ICUParagraphLayout::NextLine() (#11895)

This function calls icu::BreakIterator::createLineInstance() but does not clean up after it.

Instead use a static instance that is cloned (for thread-safety) and deleted as necessary.
5 files changed with 45 insertions and 4 deletions:
0 comments (0 inline, 0 general)
src/gfx_layout.cpp
Show inline comments
 
@@ -335,6 +335,16 @@ Font *Layouter::GetFont(FontSize size, T
 
}
 

	
 
/**
 
 * Perform initialization of layout engine.
 
 */
 
void Layouter::Initialize()
 
{
 
#if defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ)
 
	ICUParagraphLayoutFactory::InitializeLayouter();
 
#endif /* WITH_ICU_I18N && WITH_HARFBUZZ */
 
}
 

	
 
/**
 
 * Reset cached font information.
 
 * @param size Font size to reset.
 
 */
src/gfx_layout.h
Show inline comments
 
@@ -179,6 +179,7 @@ public:
 
	Point GetCharPosition(std::string_view::const_iterator ch) const;
 
	ptrdiff_t GetCharAtPosition(int x, size_t line_index) const;
 

	
 
	static void Initialize();
 
	static void ResetFontCache(FontSize size);
 
	static void ResetLineCache();
 
	static void ReduceLineCache();
src/gfx_layout_icu.cpp
Show inline comments
 
@@ -381,6 +381,30 @@ std::vector<ICURun> ItemizeStyle(std::ve
 
	return new ICUParagraphLayout(runs, buff, length);
 
}
 

	
 
/* static */ std::unique_ptr<icu::BreakIterator> ICUParagraphLayoutFactory::break_iterator;
 

	
 
/**
 
 * Initialize data needed for the ICU layouter.
 
 */
 
/* static */ void ICUParagraphLayoutFactory::InitializeLayouter()
 
{
 
	auto locale = icu::Locale(_current_language->isocode);
 
	UErrorCode status = U_ZERO_ERROR;
 
	ICUParagraphLayoutFactory::break_iterator.reset(icu::BreakIterator::createLineInstance(locale, status));
 
	assert(U_SUCCESS(status));
 
}
 

	
 
/**
 
 * Get a thread-safe line break iterator.
 
 * @returns unique_ptr managed BreakIterator instance.
 
 */
 
/* static */ std::unique_ptr<icu::BreakIterator> ICUParagraphLayoutFactory::GetBreakIterator()
 
{
 
	assert(ICUParagraphLayoutFactory::break_iterator != nullptr);
 

	
 
	return std::unique_ptr<icu::BreakIterator>(ICUParagraphLayoutFactory::break_iterator->clone());
 
}
 

	
 
std::unique_ptr<const ICUParagraphLayout::Line> ICUParagraphLayout::NextLine(int max_width)
 
{
 
	std::vector<ICURun>::iterator start_run = this->current_run;
 
@@ -413,11 +437,8 @@ std::unique_ptr<const ICUParagraphLayout
 
	/* If the text does not fit into the available width, find a suitable breaking point. */
 
	int new_partial_length = 0;
 
	if (cur_width > max_width) {
 
		auto locale = icu::Locale(_current_language->isocode);
 

	
 
		/* Create a break-iterator to find a good place to break lines. */
 
		UErrorCode err = U_ZERO_ERROR;
 
		auto break_iterator = icu::BreakIterator::createLineInstance(locale, err);
 
		auto break_iterator = ICUParagraphLayoutFactory::GetBreakIterator();
 
		break_iterator->setText(icu::UnicodeString(this->buff, this->buff_length));
 

	
 
		auto overflow_run = last_run - 1;
src/gfx_layout_icu.h
Show inline comments
 
@@ -12,6 +12,7 @@
 

	
 
#include "gfx_layout.h"
 

	
 
#include <unicode/brkiter.h>
 
#include <unicode/ustring.h>
 

	
 
/**
 
@@ -26,6 +27,11 @@ public:
 

	
 
	static ParagraphLayouter *GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping);
 
	static size_t AppendToBuffer(UChar *buff, const UChar *buffer_last, char32_t c);
 

	
 
	static void InitializeLayouter();
 
	static std::unique_ptr<icu::BreakIterator> GetBreakIterator();
 
private:
 
	static std::unique_ptr<icu::BreakIterator> break_iterator;
 
};
 

	
 
#endif /* GFX_LAYOUT_ICU_H */
src/strings.cpp
Show inline comments
 
@@ -37,6 +37,7 @@
 
#include "network/network_content_gui.h"
 
#include "newgrf_engine.h"
 
#include "core/backup_type.hpp"
 
#include "gfx_layout.h"
 
#include <stack>
 
#include <charconv>
 

	
 
@@ -1976,6 +1977,8 @@ bool ReadLanguagePack(const LanguageMeta
 
	}
 
#endif /* WITH_ICU_I18N */
 

	
 
	Layouter::Initialize();
 

	
 
	/* Some lists need to be sorted again after a language change. */
 
	ReconsiderGameScriptLanguage();
 
	InitializeSortedCargoSpecs();
0 comments (0 inline, 0 general)