summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2021-03-01 13:12:17 +0100
committerPatric Stout <github@truebrain.nl>2021-03-01 23:17:47 +0100
commit74aa934441351334e40d8963900b8a2fbc9bc9cd (patch)
tree1257efebb69111b35c5026d59c0504088faff0d8
parentd7a70c67bacef7453ae56e9136c9c16e4b19c314 (diff)
downloadopenttd-74aa934441351334e40d8963900b8a2fbc9bc9cd.tar.xz
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.
-rw-r--r--src/settings_type.h9
-rw-r--r--src/settingsgen/settingsgen.cpp139
-rw-r--r--src/table/company_settings.ini3
-rw-r--r--src/table/currency_settings.ini3
-rw-r--r--src/table/gameopt_settings.ini7
-rw-r--r--src/table/misc_settings.ini4
-rw-r--r--src/table/settings.ini8
-rw-r--r--src/table/win32_settings.ini3
-rw-r--r--src/table/window_settings.ini3
9 files changed, 122 insertions, 57 deletions
diff --git a/src/settings_type.h b/src/settings_type.h
index f2c591f64..433e8d535 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -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 {
diff --git a/src/settingsgen/settingsgen.cpp b/src/settingsgen/settingsgen.cpp
index ac3a2a85a..8dd9ff6f4 100644
--- a/src/settingsgen/settingsgen.cpp
+++ b/src/settingsgen/settingsgen.cpp
@@ -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.
@@ -240,16 +242,83 @@ static const char *FindItemValue(const char *name, IniGroup *grp, IniGroup *defa
}
/**
+ * 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);
diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini
index e685ff6dc..eea2371fc 100644
--- a/src/table/company_settings.ini
+++ b/src/table/company_settings.ini
@@ -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
diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini
index 7ff879964..c242c83a8 100644
--- a/src/table/currency_settings.ini
+++ b/src/table/currency_settings.ini
@@ -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
diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini
index b85e11d9c..c4140f428 100644
--- a/src/table/gameopt_settings.ini
+++ b/src/table/gameopt_settings.ini
@@ -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
diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini
index 3add5148f..9d2f76cc0 100644
--- a/src/table/misc_settings.ini
+++ b/src/table/misc_settings.ini
@@ -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
diff --git a/src/table/settings.ini b/src/table/settings.ini
index dd0ecfee5..b48ac6cd6 100644
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -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
diff --git a/src/table/win32_settings.ini b/src/table/win32_settings.ini
index 406e8dd8f..c3cc45014 100644
--- a/src/table/win32_settings.ini
+++ b/src/table/win32_settings.ini
@@ -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
diff --git a/src/table/window_settings.ini b/src/table/window_settings.ini
index e336d6447..fb252076c 100644
--- a/src/table/window_settings.ini
+++ b/src/table/window_settings.ini
@@ -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