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

Change: Don't handle 'missing' string parameters as 0. #11673

Merged
merged 1 commit into from Jan 4, 2024

Conversation

PeterN
Copy link
Member

@PeterN PeterN commented Jan 3, 2024

Motivation / Problem

If not enough parameters are supplied for a string, then a value of 0 was used, which could result in incorrect information being displayed.

Players may not notice there is an issue.

image

Description

Instead, throw an exception and include an error in the string. This is non-translatable, like existing string error messages.

image

Limitations

This is not intended as a fix for GSText compatibility, that is another issue :)

Checklist for review

Some things are not automated, and forgotten often. This list is a reminder for the reviewers.

  • The bug fix is important enough to be backported? (label: 'backport requested')
  • This PR touches english.txt or translations? Check the guidelines
  • This PR affects the save game format? (label 'savegame upgrade')
  • This PR affects the GS/AI API? (label 'needs review: Script API')
    • ai_changelog.hpp, game_changelog.hpp need updating.
    • The compatibility wrappers (compat_*.nut) need updating.
  • This PR affects the NewGRF API? (label 'needs review: NewGRF')

src/strings.cpp Outdated
Comment on lines 926 to 1632
case VEH_AIRCRAFT: string_id = STR_SV_AIRCRAFT_NAME; break;
case SCC_WAYPOINT_NAME: { // {WAYPOINT}
Waypoint *wp = Waypoint::GetIfValid(args.GetNextParameter<StationID>());
if (wp == nullptr) break;

if (!wp->name.empty()) {
auto tmp_params = MakeParameters(wp->name);
GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
} else {
auto tmp_params = MakeParameters(wp->town->index, wp->town_cn + 1);
StringID string_id = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
if (wp->town_cn != 0) string_id++;
GetStringWithArgs(builder, string_id, tmp_params);
}
break;
}

GetStringWithArgs(builder, string_id, tmp_params);
case SCC_VEHICLE_NAME: { // {VEHICLE}
const Vehicle *v = Vehicle::GetIfValid(args.GetNextParameter<VehicleID>());
if (v == nullptr) break;

if (!v->name.empty()) {
auto tmp_params = MakeParameters(v->name);
GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
} else if (v->group_id != DEFAULT_GROUP) {
/* The vehicle has no name, but is member of a group, so print group name */
auto tmp_params = MakeParameters(v->group_id, v->unitnumber);
GetStringWithArgs(builder, STR_FORMAT_GROUP_VEHICLE_NAME, tmp_params);
} else {
auto tmp_params = MakeParameters(v->unitnumber);

StringID string_id;
switch (v->type) {
default: string_id = STR_INVALID_VEHICLE; break;
case VEH_TRAIN: string_id = STR_SV_TRAIN_NAME; break;
case VEH_ROAD: string_id = STR_SV_ROAD_VEHICLE_NAME; break;
case VEH_SHIP: string_id = STR_SV_SHIP_NAME; break;
case VEH_AIRCRAFT: string_id = STR_SV_AIRCRAFT_NAME; break;
}

GetStringWithArgs(builder, string_id, tmp_params);
}
break;
}
break;
}

case SCC_SIGN_NAME: { // {SIGN}
const Sign *si = Sign::GetIfValid(args.GetNextParameter<SignID>());
if (si == nullptr) break;
case SCC_SIGN_NAME: { // {SIGN}
const Sign *si = Sign::GetIfValid(args.GetNextParameter<SignID>());
if (si == nullptr) break;

if (!si->name.empty()) {
auto tmp_params = MakeParameters(si->name);
GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
} else {
auto tmp_params = ArrayStringParameters<0>();
GetStringWithArgs(builder, STR_DEFAULT_SIGN_NAME, tmp_params);
if (!si->name.empty()) {
auto tmp_params = MakeParameters(si->name);
GetStringWithArgs(builder, STR_JUST_RAW_STRING, tmp_params);
} else {
auto tmp_params = ArrayStringParameters<0>();
GetStringWithArgs(builder, STR_DEFAULT_SIGN_NAME, tmp_params);
}
break;
}
break;
}

case SCC_STATION_FEATURES: { // {STATIONFEATURES}
StationGetSpecialString(builder, args.GetNextParameter<StationFacility>());
break;
}
case SCC_STATION_FEATURES: { // {STATIONFEATURES}
StationGetSpecialString(builder, args.GetNextParameter<StationFacility>());
break;
}

case SCC_COLOUR: { // {COLOUR}
StringControlCode scc = (StringControlCode)(SCC_BLUE + args.GetNextParameter<Colours>());
if (IsInsideMM(scc, SCC_BLUE, SCC_COLOUR)) builder.Utf8Encode(scc);
break;
}
case SCC_COLOUR: { // {COLOUR}
StringControlCode scc = (StringControlCode)(SCC_BLUE + args.GetNextParameter<Colours>());
if (IsInsideMM(scc, SCC_BLUE, SCC_COLOUR)) builder.Utf8Encode(scc);
break;
}

default:
builder.Utf8Encode(b);
break;
default:
builder.Utf8Encode(b);
break;
}

Check notice

Code scanning / CodeQL

Long switch case Note

Switch has at least one case that is too long:
SCC_ENCODED (81 lines)
.
Switch has at least one case that is too long:
SCC_GENDER_LIST (32 lines)
.
Switch has at least one case that is too long:
SCC_CARGO_SHORT (33 lines)
.
Switch has at least one case that is too long:
SCC_ENGINE_NAME (31 lines)
.
Switch has at least one case that is too long:
SCC_STATION_NAME (39 lines)
.
src/strings.cpp Outdated Show resolved Hide resolved
src/strings.cpp Outdated Show resolved Hide resolved
src/strings.cpp Outdated Show resolved Hide resolved
src/strings.cpp Outdated Show resolved Hide resolved
@glx22
Copy link
Contributor

glx22 commented Jan 3, 2024

PeterN/OpenTTD@invalid-parameters...glx22:OpenTTD:pr/11673 tested with

		local text = GSText(GSText.STR_TEST);
		text.SetParam(1, GSText(GSText.STR_FOO, "foo"));
		text.SetParam(2, GSWindow.TC_RED);
		text.SetParam(3, 42);
		GSTown.SetText(0, text);

and

STR_TEST :{STRING} - {COLOUR}{NUM} is supposed to be 42
STR_FOO  :'{RAW_STRING}'

seems to show what I (and ScriptText validation) expect
image
encoded string is
image

Of course debug console is full of dbg: [misc] FormatString: Trying to read string parameter with wrong type
I disabled the debug line for game scripts.

@PeterN
Copy link
Member Author

PeterN commented Jan 3, 2024

I've removed the second commit now because it was obviously wrong, and I think it can be raised in a separate PR.

src/strings.cpp Outdated
Comment on lines 1108 to 1112
/* raw_string can be(come) nullptr when the parameter is out of range and 0 is returned instead. */
if (raw_string == nullptr) {
builder += "(invalid RAW_STRING parameter)";
case SCC_RAW_STRING_POINTER: { // {RAW_STRING}
const char *raw_string = args.GetNextParameterString();
FormatString(builder, raw_string, args);
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could also be nullptr when you, for whatever reason, pass nullptr to SetDParamStr. You can currently do that, and it will also trigger this code.
The question is whether we want to game to crash here, or should we maybe add an assert in SetDParamStr where applicable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's still possible then I'll put it back to how it was I was misinformed :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe replace the comment with /* raw_string can be nullptr. */, i.e. remove the bit about the parameter being out of range.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, the comment was misleading :)

If not enough parameters are supplied for a string, then a value of 0 was used, which could result in incorrect information being displayed.

Instead, throw an exception and include an error in the string.
@PeterN PeterN merged commit 7482f71 into OpenTTD:master Jan 4, 2024
20 checks passed
@PeterN PeterN deleted the invalid-parameters branch January 4, 2024 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants