summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2023-11-02 15:47:33 +0000
committerTom Lane2023-11-02 15:47:33 +0000
commit7704a1a72e879daaefa1742916e01505edd2ce47 (patch)
tree2d5e3c8bf010a6c6a70ec34a4202e467b447ef7a
parent4b14e18714e10ac930ca53938fc6fa1a4fda50c7 (diff)
Be more wary about NULL values for GUC string variables.
get_explain_guc_options() crashed if a string GUC marked GUC_EXPLAIN has a NULL boot_val. Nosing around found a couple of other places that seemed insufficiently cautious about NULL string values, although those are likely unreachable in practice. Add some commentary defining the expectations for NULL values of string variables, in hopes of forestalling future additions of more such bugs. Xing Guo, Aleksander Alekseev, Tom Lane Discussion: https://postgr.es/m/CACpMh+AyDx5YUpPaAgzVwC1d8zfOL4JoD-uyFDnNSa1z0EsDQQ@mail.gmail.com
-rw-r--r--src/backend/utils/misc/guc.c16
-rw-r--r--src/include/utils/guc_tables.h10
2 files changed, 23 insertions, 3 deletions
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 39d3775e801..d6cd009f239 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1473,7 +1473,9 @@ check_GUC_init(struct config_generic *gconf)
{
struct config_string *conf = (struct config_string *) gconf;
- if (*conf->variable != NULL && strcmp(*conf->variable, conf->boot_val) != 0)
+ if (*conf->variable != NULL &&
+ (conf->boot_val == NULL ||
+ strcmp(*conf->variable, conf->boot_val) != 0))
{
elog(LOG, "GUC (PGC_STRING) %s, boot_val=%s, C-var=%s",
conf->gen.name, conf->boot_val ? conf->boot_val : "<null>", *conf->variable);
@@ -5255,7 +5257,14 @@ get_explain_guc_options(int *num)
{
struct config_string *lconf = (struct config_string *) conf;
- modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0);
+ if (lconf->boot_val == NULL &&
+ *lconf->variable == NULL)
+ modified = false;
+ else if (lconf->boot_val == NULL ||
+ *lconf->variable == NULL)
+ modified = true;
+ else
+ modified = (strcmp(lconf->boot_val, *(lconf->variable)) != 0);
}
break;
@@ -5482,7 +5491,8 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf)
{
struct config_string *conf = (struct config_string *) gconf;
- fprintf(fp, "%s", *conf->variable);
+ if (*conf->variable)
+ fprintf(fp, "%s", *conf->variable);
}
break;
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 1ec95755700..0c382559617 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -240,6 +240,16 @@ struct config_real
void *reset_extra;
};
+/*
+ * A note about string GUCs: the boot_val is allowed to be NULL, which leads
+ * to the reset_val and the actual variable value (*variable) also being NULL.
+ * However, there is no way to set a NULL value subsequently using
+ * set_config_option or any other GUC API. Also, GUC APIs such as SHOW will
+ * display a NULL value as an empty string. Callers that choose to use a NULL
+ * boot_val should overwrite the setting later in startup, or else be careful
+ * that NULL doesn't have semantics that are visibly different from an empty
+ * string.
+ */
struct config_string
{
struct config_generic gen;