Fix: TextfileWindow called virtual methods before constructor completed. (#11889)

SetStringParameters() was called during widget tree init in the constructor.

Calls within a constructor cannot call the derived classes methods. This would result in invalid data being passed to the string system, which could then crash.

(cherry picked from commit fef0bfcfd3)
This commit is contained in:
Peter Nelson
2024-01-27 14:45:37 +00:00
committed by Jonathan G Rennison
parent a7c2f489f6
commit 4bf9c123d3
8 changed files with 22 additions and 4 deletions

View File

@@ -59,6 +59,8 @@ static std::optional<std::string> FindGameManualFilePath(std::string_view filena
struct GameManualTextfileWindow : public TextfileWindow { struct GameManualTextfileWindow : public TextfileWindow {
GameManualTextfileWindow(std::string_view filename) : TextfileWindow(TFT_GAME_MANUAL) GameManualTextfileWindow(std::string_view filename) : TextfileWindow(TFT_GAME_MANUAL)
{ {
this->ConstructWindow();
/* Mark the content of these files as trusted. */ /* Mark the content of these files as trusted. */
this->trusted = true; this->trusted = true;

View File

@@ -44,6 +44,8 @@ struct ContentTextfileWindow : public TextfileWindow {
ContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) : TextfileWindow(file_type), ci(ci) ContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) : TextfileWindow(file_type), ci(ci)
{ {
this->ConstructWindow();
const char *textfile = this->ci->GetTextfile(file_type); const char *textfile = this->ci->GetTextfile(file_type);
this->LoadTextfile(textfile, GetContentInfoSubDir(this->ci->type)); this->LoadTextfile(textfile, GetContentInfoSubDir(this->ci->type));
} }

View File

@@ -2571,6 +2571,8 @@ struct SurveyResultTextfileWindow : public TextfileWindow {
SurveyResultTextfileWindow(TextfileType file_type) : TextfileWindow(file_type) SurveyResultTextfileWindow(TextfileType file_type) : TextfileWindow(file_type)
{ {
this->ConstructWindow();
auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::PREVIEW, true); auto result = _survey.CreatePayload(NetworkSurveyHandler::Reason::PREVIEW, true);
this->LoadText(result); this->LoadText(result);
this->InvalidateData(); this->InvalidateData();

View File

@@ -573,6 +573,8 @@ struct NewGRFTextfileWindow : public TextfileWindow {
NewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) : TextfileWindow(file_type), grf_config(c) NewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) : TextfileWindow(file_type), grf_config(c)
{ {
this->ConstructWindow();
const char *textfile = this->grf_config->GetTextfile(file_type); const char *textfile = this->grf_config->GetTextfile(file_type);
this->LoadTextfile(textfile, NEWGRF_DIR); this->LoadTextfile(textfile, NEWGRF_DIR);
} }

View File

@@ -649,6 +649,7 @@ struct ScriptTextfileWindow : public TextfileWindow {
ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot) ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot)
{ {
this->ConstructWindow();
this->OnInvalidateData(); this->OnInvalidateData();
} }

View File

@@ -105,6 +105,8 @@ struct BaseSetTextfileWindow : public TextfileWindow {
BaseSetTextfileWindow(TextfileType file_type, const TBaseSet *baseset, StringID content_type) : TextfileWindow(file_type), baseset(baseset), content_type(content_type) BaseSetTextfileWindow(TextfileType file_type, const TBaseSet *baseset, StringID content_type) : TextfileWindow(file_type), baseset(baseset), content_type(content_type)
{ {
this->ConstructWindow();
const char *textfile = this->baseset->GetTextfile(file_type); const char *textfile = this->baseset->GetTextfile(file_type);
this->LoadTextfile(textfile, BASESET_DIR); this->LoadTextfile(textfile, BASESET_DIR);
} }

View File

@@ -84,13 +84,19 @@ static WindowDesc _textfile_desc(__FILE__, __LINE__,
); );
TextfileWindow::TextfileWindow(TextfileType file_type) : Window(&_textfile_desc), file_type(file_type) TextfileWindow::TextfileWindow(TextfileType file_type) : Window(&_textfile_desc), file_type(file_type)
{
/* Init of nested tree is deferred.
* TextfileWindow::ConstructWindow must be called by the inheriting window. */
}
void TextfileWindow::ConstructWindow()
{ {
this->CreateNestedTree(); this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_TF_VSCROLLBAR); this->vscroll = this->GetScrollbar(WID_TF_VSCROLLBAR);
this->hscroll = this->GetScrollbar(WID_TF_HSCROLLBAR); this->hscroll = this->GetScrollbar(WID_TF_HSCROLLBAR);
this->GetWidget<NWidgetCore>(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); this->GetWidget<NWidgetCore>(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + this->file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
this->GetWidget<NWidgetStacked>(WID_TF_SEL_JUMPLIST)->SetDisplayedPlane(SZSP_HORIZONTAL); this->GetWidget<NWidgetStacked>(WID_TF_SEL_JUMPLIST)->SetDisplayedPlane(SZSP_HORIZONTAL);
this->FinishInitNested(file_type); this->FinishInitNested(this->file_type);
this->DisableWidget(WID_TF_NAVBACK); this->DisableWidget(WID_TF_NAVBACK);
this->DisableWidget(WID_TF_NAVFORWARD); this->DisableWidget(WID_TF_NAVFORWARD);

View File

@@ -30,8 +30,6 @@ struct TextfileWindow : public Window, MissingGlyphSearcher {
Scrollbar *vscroll; ///< Vertical scrollbar. Scrollbar *vscroll; ///< Vertical scrollbar.
Scrollbar *hscroll; ///< Horizontal scrollbar. Scrollbar *hscroll; ///< Horizontal scrollbar.
TextfileWindow(TextfileType file_type);
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override; void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override;
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override; void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override;
void DrawWidget(const Rect &r, WidgetID widget) const override; void DrawWidget(const Rect &r, WidgetID widget) const override;
@@ -54,6 +52,9 @@ struct TextfileWindow : public Window, MissingGlyphSearcher {
} }
protected: protected:
TextfileWindow(TextfileType file_type);
void ConstructWindow();
struct Line { struct Line {
int top{0}; ///< Top scroll position in visual lines. int top{0}; ///< Top scroll position in visual lines.
int bottom{0}; ///< Bottom scroll position in visual lines. int bottom{0}; ///< Bottom scroll position in visual lines.