mirror of https://github.com/OpenTTD/OpenTTD
Codechange: validate that "max" value of settings fit in their storage
This is an easy mistake to make, so protect us against making such mistakes, by validating it doesn't happen.pull/8795/head
parent
d7a70c67ba
commit
74aa934441
|
@ -21,6 +21,15 @@
|
|||
#include "zoom_type.h"
|
||||
#include "openttd.h"
|
||||
|
||||
/* Used to validate sizes of "max" value in settings. */
|
||||
const size_t MAX_SLE_UINT8 = UINT8_MAX;
|
||||
const size_t MAX_SLE_UINT16 = UINT16_MAX;
|
||||
const size_t MAX_SLE_UINT32 = UINT32_MAX;
|
||||
const size_t MAX_SLE_UINT = UINT_MAX;
|
||||
const size_t MAX_SLE_INT8 = INT8_MAX;
|
||||
const size_t MAX_SLE_INT16 = INT16_MAX;
|
||||
const size_t MAX_SLE_INT32 = INT32_MAX;
|
||||
const size_t MAX_SLE_INT = INT_MAX;
|
||||
|
||||
/** Settings profiles and highscore tables. */
|
||||
enum SettingsProfile {
|
||||
|
|
|
@ -186,11 +186,13 @@ struct SettingsIniFile : IniLoadFile {
|
|||
};
|
||||
|
||||
OutputStore _stored_output; ///< Temporary storage of the output, until all processing is done.
|
||||
OutputStore _post_amble_output; ///< Similar to _stored_output, but for the post amble.
|
||||
|
||||
static const char *PREAMBLE_GROUP_NAME = "pre-amble"; ///< Name of the group containing the pre amble.
|
||||
static const char *PREAMBLE_GROUP_NAME = "pre-amble"; ///< Name of the group containing the pre amble.
|
||||
static const char *POSTAMBLE_GROUP_NAME = "post-amble"; ///< Name of the group containing the post amble.
|
||||
static const char *TEMPLATES_GROUP_NAME = "templates"; ///< Name of the group containing the templates.
|
||||
static const char *DEFAULTS_GROUP_NAME = "defaults"; ///< Name of the group containing default values for the template variables.
|
||||
static const char *TEMPLATES_GROUP_NAME = "templates"; ///< Name of the group containing the templates.
|
||||
static const char *VALIDATION_GROUP_NAME = "validation"; ///< Name of the group containing the validation statements.
|
||||
static const char *DEFAULTS_GROUP_NAME = "defaults"; ///< Name of the group containing default values for the template variables.
|
||||
|
||||
/**
|
||||
* Load the INI file.
|
||||
|
@ -239,17 +241,84 @@ static const char *FindItemValue(const char *name, IniGroup *grp, IniGroup *defa
|
|||
return item->value->c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single entry via a template and output this.
|
||||
* @param item The template to use for the output.
|
||||
* @param grp Group current being used for template rendering.
|
||||
* @param default_grp Default values for items not set in @grp.
|
||||
* @param output Output to use for result.
|
||||
*/
|
||||
static void DumpLine(IniItem *item, IniGroup *grp, IniGroup *default_grp, OutputStore &output)
|
||||
{
|
||||
static const int MAX_VAR_LENGTH = 64;
|
||||
|
||||
/* Prefix with #if/#ifdef/#ifndef */
|
||||
static const char * const pp_lines[] = {"if", "ifdef", "ifndef", nullptr};
|
||||
int count = 0;
|
||||
for (const char * const *name = pp_lines; *name != nullptr; name++) {
|
||||
const char *condition = FindItemValue(*name, grp, default_grp);
|
||||
if (condition != nullptr) {
|
||||
output.Add("#", 1);
|
||||
output.Add(*name);
|
||||
output.Add(" ", 1);
|
||||
output.Add(condition);
|
||||
output.Add("\n", 1);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output text of the template, except template variables of the form '$[_a-z0-9]+' which get replaced by their value. */
|
||||
const char *txt = item->value->c_str();
|
||||
while (*txt != '\0') {
|
||||
if (*txt != '$') {
|
||||
output.Add(txt, 1);
|
||||
txt++;
|
||||
continue;
|
||||
}
|
||||
txt++;
|
||||
if (*txt == '$') { // Literal $
|
||||
output.Add(txt, 1);
|
||||
txt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read variable. */
|
||||
char variable[MAX_VAR_LENGTH];
|
||||
int i = 0;
|
||||
while (i < MAX_VAR_LENGTH - 1) {
|
||||
if (!(txt[i] == '_' || (txt[i] >= 'a' && txt[i] <= 'z') || (txt[i] >= '0' && txt[i] <= '9'))) break;
|
||||
variable[i] = txt[i];
|
||||
i++;
|
||||
}
|
||||
variable[i] = '\0';
|
||||
txt += i;
|
||||
|
||||
if (i > 0) {
|
||||
/* Find the text to output. */
|
||||
const char *valitem = FindItemValue(variable, grp, default_grp);
|
||||
if (valitem != nullptr) output.Add(valitem);
|
||||
} else {
|
||||
output.Add("$", 1);
|
||||
}
|
||||
}
|
||||
output.Add("\n", 1); // \n after the expanded template.
|
||||
while (count > 0) {
|
||||
output.Add("#endif\n");
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output all non-special sections through the template / template variable expansion system.
|
||||
* @param ifile Loaded INI data.
|
||||
*/
|
||||
static void DumpSections(IniLoadFile *ifile)
|
||||
{
|
||||
static const int MAX_VAR_LENGTH = 64;
|
||||
static const char * const special_group_names[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, DEFAULTS_GROUP_NAME, TEMPLATES_GROUP_NAME, nullptr};
|
||||
static const char * const special_group_names[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, DEFAULTS_GROUP_NAME, TEMPLATES_GROUP_NAME, VALIDATION_GROUP_NAME, nullptr};
|
||||
|
||||
IniGroup *default_grp = ifile->GetGroup(DEFAULTS_GROUP_NAME, false);
|
||||
IniGroup *templates_grp = ifile->GetGroup(TEMPLATES_GROUP_NAME, false);
|
||||
IniGroup *validation_grp = ifile->GetGroup(VALIDATION_GROUP_NAME, false);
|
||||
if (templates_grp == nullptr) return;
|
||||
|
||||
/* Output every group, using its name as template name. */
|
||||
|
@ -263,61 +332,14 @@ static void DumpSections(IniLoadFile *ifile)
|
|||
fprintf(stderr, "settingsgen: Warning: Cannot find template %s\n", grp->name.c_str());
|
||||
continue;
|
||||
}
|
||||
DumpLine(template_item, grp, default_grp, _stored_output);
|
||||
|
||||
/* Prefix with #if/#ifdef/#ifndef */
|
||||
static const char * const pp_lines[] = {"if", "ifdef", "ifndef", nullptr};
|
||||
int count = 0;
|
||||
for (const char * const *name = pp_lines; *name != nullptr; name++) {
|
||||
const char *condition = FindItemValue(*name, grp, default_grp);
|
||||
if (condition != nullptr) {
|
||||
_stored_output.Add("#", 1);
|
||||
_stored_output.Add(*name);
|
||||
_stored_output.Add(" ", 1);
|
||||
_stored_output.Add(condition);
|
||||
_stored_output.Add("\n", 1);
|
||||
count++;
|
||||
if (validation_grp != nullptr) {
|
||||
IniItem *validation_item = validation_grp->GetItem(grp->name, false); // Find template value.
|
||||
if (validation_item != nullptr && validation_item->value.has_value()) {
|
||||
DumpLine(validation_item, grp, default_grp, _post_amble_output);
|
||||
}
|
||||
}
|
||||
|
||||
/* Output text of the template, except template variables of the form '$[_a-z0-9]+' which get replaced by their value. */
|
||||
const char *txt = template_item->value->c_str();
|
||||
while (*txt != '\0') {
|
||||
if (*txt != '$') {
|
||||
_stored_output.Add(txt, 1);
|
||||
txt++;
|
||||
continue;
|
||||
}
|
||||
txt++;
|
||||
if (*txt == '$') { // Literal $
|
||||
_stored_output.Add(txt, 1);
|
||||
txt++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read variable. */
|
||||
char variable[MAX_VAR_LENGTH];
|
||||
int i = 0;
|
||||
while (i < MAX_VAR_LENGTH - 1) {
|
||||
if (!(txt[i] == '_' || (txt[i] >= 'a' && txt[i] <= 'z') || (txt[i] >= '0' && txt[i] <= '9'))) break;
|
||||
variable[i] = txt[i];
|
||||
i++;
|
||||
}
|
||||
variable[i] = '\0';
|
||||
txt += i;
|
||||
|
||||
if (i > 0) {
|
||||
/* Find the text to output. */
|
||||
const char *valitem = FindItemValue(variable, grp, default_grp);
|
||||
if (valitem != nullptr) _stored_output.Add(valitem);
|
||||
} else {
|
||||
_stored_output.Add("$", 1);
|
||||
}
|
||||
}
|
||||
_stored_output.Add("\n", 1); // \n after the expanded template.
|
||||
while (count > 0) {
|
||||
_stored_output.Add("#endif\n");
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,6 +498,7 @@ int CDECL main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
_stored_output.Clear();
|
||||
_post_amble_output.Clear();
|
||||
|
||||
for (int i = 0; i < mgo.numleft; i++) ProcessIniFile(mgo.argv[i]);
|
||||
|
||||
|
@ -483,6 +506,7 @@ int CDECL main(int argc, char *argv[])
|
|||
if (output_file == nullptr) {
|
||||
CopyFile(before_file, stdout);
|
||||
_stored_output.Write(stdout);
|
||||
_post_amble_output.Write(stdout);
|
||||
CopyFile(after_file, stdout);
|
||||
} else {
|
||||
static const char * const tmp_output = "tmp2.xxx";
|
||||
|
@ -494,6 +518,7 @@ int CDECL main(int argc, char *argv[])
|
|||
}
|
||||
CopyFile(before_file, fp);
|
||||
_stored_output.Write(fp);
|
||||
_post_amble_output.Write(fp);
|
||||
CopyFile(after_file, fp);
|
||||
fclose(fp);
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def,
|
|||
SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup),
|
||||
SDT_END = SDT_END()
|
||||
|
||||
[validation]
|
||||
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
flags = 0
|
||||
guiflags = SGF_PER_COMPANY
|
||||
|
|
|
@ -14,6 +14,9 @@ SDT_CHR = SDT_CHR($base, $var, $flags, $guiflags, $def,
|
|||
SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup),
|
||||
SDT_END = SDT_END()
|
||||
|
||||
[validation]
|
||||
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||
guiflags = SGF_NONE
|
||||
|
|
|
@ -46,6 +46,13 @@ SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $ma
|
|||
SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup),
|
||||
SDT_END = SDT_END()
|
||||
|
||||
[validation]
|
||||
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDTG_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDTC_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDT_OMANY = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
flags = 0
|
||||
guiflags = SGF_NONE
|
||||
|
|
|
@ -26,6 +26,10 @@ SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def,
|
|||
SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup),
|
||||
SDTG_END = SDTG_END()
|
||||
|
||||
[validation]
|
||||
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDTG_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||
guiflags = SGF_NONE
|
||||
|
|
|
@ -77,6 +77,14 @@ SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min,
|
|||
SDT_NULL = SDT_NULL($length, $from, $to),
|
||||
SDT_END = SDT_END()
|
||||
|
||||
[validation]
|
||||
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDTG_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDTC_OMANY = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDTC_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
SDT_OMANY = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
flags = 0
|
||||
guiflags = SGF_NONE
|
||||
|
|
|
@ -18,6 +18,9 @@ SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def,
|
|||
SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup),
|
||||
SDTG_END = SDTG_END()
|
||||
|
||||
[validation]
|
||||
SDTG_VAR = static_assert($max <= MAX_$type, "Maximum value for $var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||
guiflags = SGF_NONE
|
||||
|
|
|
@ -14,6 +14,9 @@ SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def,
|
|||
SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup),
|
||||
SDT_END = SDT_END()
|
||||
|
||||
[validation]
|
||||
SDT_VAR = static_assert($max <= MAX_$type, "Maximum value for $base.$var exceeds storage size");
|
||||
|
||||
[defaults]
|
||||
base = WindowDesc
|
||||
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||
|
|
Loading…
Reference in New Issue