]> granicus.if.org Git - postgresql/commitdiff
Prevent integer overflows during units conversion when displaying a GUC
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 6 Jul 2008 19:48:45 +0000 (19:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 6 Jul 2008 19:48:45 +0000 (19:48 +0000)
variable that has units.  Per report from Stefan Kaltenbrunner.

Backport to 8.2.  I also backported my patch of 2007-06-21 that prevented
comparable overflows on the input side, since that now seems to have enough
field track record to be back-patched safely.  That patch included addition
of hints listing the available unit names, which I did not bother to strip
out of it --- this will make a little more work for the translators, but
they can copy the translation from 8.3, and anyway an untranslated hint
is better than no hint.

src/backend/utils/misc/guc.c

index 60b2fead7d7f85a160282c8a88ad7f8d5b46f144..96e05fdc232bd23339ce3d050b288a40de8228ec 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.461 2008/07/01 21:07:33 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.462 2008/07/06 19:48:45 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -6266,10 +6266,18 @@ _ShowOption(struct config_generic * record, bool use_units)
                                        val = (*conf->show_hook) ();
                                else
                                {
-                                       char            unit[4];
-                                       int                     result = *conf->variable;
+                                       /*
+                                        * Use int64 arithmetic to avoid overflows in units
+                                        * conversion.  If INT64_IS_BUSTED we might overflow
+                                        * anyway and print bogus answers, but there are few
+                                        * enough such machines that it doesn't seem worth
+                                        * trying harder.
+                                        */
+                                       int64           result = *conf->variable;
+                                       const char *unit;
 
-                                       if (use_units && result > 0 && (record->flags & GUC_UNIT_MEMORY))
+                                       if (use_units && result > 0 &&
+                                               (record->flags & GUC_UNIT_MEMORY))
                                        {
                                                switch (record->flags & GUC_UNIT_MEMORY)
                                                {
@@ -6284,19 +6292,20 @@ _ShowOption(struct config_generic * record, bool use_units)
                                                if (result % KB_PER_GB == 0)
                                                {
                                                        result /= KB_PER_GB;
-                                                       strcpy(unit, "GB");
+                                                       unit = "GB";
                                                }
                                                else if (result % KB_PER_MB == 0)
                                                {
                                                        result /= KB_PER_MB;
-                                                       strcpy(unit, "MB");
+                                                       unit = "MB";
                                                }
                                                else
                                                {
-                                                       strcpy(unit, "kB");
+                                                       unit = "kB";
                                                }
                                        }
-                                       else if (use_units && result > 0 && (record->flags & GUC_UNIT_TIME))
+                                       else if (use_units && result > 0 &&
+                                                        (record->flags & GUC_UNIT_TIME))
                                        {
                                                switch (record->flags & GUC_UNIT_TIME)
                                                {
@@ -6311,33 +6320,33 @@ _ShowOption(struct config_generic * record, bool use_units)
                                                if (result % MS_PER_D == 0)
                                                {
                                                        result /= MS_PER_D;
-                                                       strcpy(unit, "d");
+                                                       unit = "d";
                                                }
                                                else if (result % MS_PER_H == 0)
                                                {
                                                        result /= MS_PER_H;
-                                                       strcpy(unit, "h");
+                                                       unit = "h";
                                                }
                                                else if (result % MS_PER_MIN == 0)
                                                {
                                                        result /= MS_PER_MIN;
-                                                       strcpy(unit, "min");
+                                                       unit = "min";
                                                }
                                                else if (result % MS_PER_S == 0)
                                                {
                                                        result /= MS_PER_S;
-                                                       strcpy(unit, "s");
+                                                       unit = "s";
                                                }
                                                else
                                                {
-                                                       strcpy(unit, "ms");
+                                                       unit = "ms";
                                                }
                                        }
                                        else
-                                               strcpy(unit, "");
+                                               unit = "";
 
-                                       snprintf(buffer, sizeof(buffer), "%d%s",
-                                                        (int) result, unit);
+                                       snprintf(buffer, sizeof(buffer), INT64_FORMAT "%s",
+                                                        result, unit);
                                        val = buffer;
                                }
                        }