summaryrefslogtreecommitdiff
path: root/src
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 /src
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.
Diffstat (limited to 'src')
-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