]> granicus.if.org Git - postgresql/commitdiff
pgbench: Install guards against obscure overflow conditions.
authorRobert Haas <rhaas@postgresql.org>
Mon, 1 Feb 2016 13:23:41 +0000 (08:23 -0500)
committerRobert Haas <rhaas@postgresql.org>
Mon, 1 Feb 2016 13:23:41 +0000 (08:23 -0500)
Dividing INT_MIN by -1 or taking INT_MIN modulo -1 can sometimes
cause floating-point exceptions or otherwise misbehave.

Fabien Coelho and Michael Paquier

src/bin/pgbench/pgbench.c

index 44da3d19c19c36c0636c304cc56d70c5d3e5332f..9bd822299b268cea9d78f29bff467454f15b9ded 100644 (file)
@@ -1047,7 +1047,29 @@ evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval)
                                                        fprintf(stderr, "division by zero\n");
                                                        return false;
                                                }
-                                               *retval = lval / rval;
+
+                                               /*
+                                                * INT64_MIN / -1 is problematic, since the result
+                                                * can't be represented on a two's-complement machine.
+                                                * Some machines produce INT64_MIN, some produce zero,
+                                                * some throw an exception. We can dodge the problem
+                                                * by recognizing that division by -1 is the same as
+                                                * negation.
+                                                */
+                                               if (rval == -1)
+                                               {
+                                                       *retval = -lval;
+
+                                                       /* overflow check (needed for INT64_MIN) */
+                                                       if (lval == PG_INT64_MIN)
+                                                       {
+                                                               fprintf(stderr, "bigint out of range\n");
+                                                               return false;
+                                                       }
+                                               }
+                                               else
+                                                       *retval = lval / rval;
+
                                                return true;
 
                                        case '%':
@@ -1056,7 +1078,17 @@ evaluateExpr(CState *st, PgBenchExpr *expr, int64 *retval)
                                                        fprintf(stderr, "division by zero\n");
                                                        return false;
                                                }
-                                               *retval = lval % rval;
+
+                                               /*
+                                                * Some machines throw a floating-point exception for
+                                                * INT64_MIN % -1.  Dodge that problem by noting that
+                                                * any value modulo -1 is 0.
+                                                */
+                                               if (rval == -1)
+                                                       *retval = 0;
+                                               else
+                                                       *retval = lval % rval;
+
                                                return true;
                                }