Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
pgbench: Install guard against overflow when dividing by -1.
authorRobert Haas <rhaas@postgresql.org>
Wed, 3 Feb 2016 14:15:29 +0000 (09:15 -0500)
committerRobert Haas <rhaas@postgresql.org>
Wed, 3 Feb 2016 14:19:58 +0000 (09:19 -0500)
Commit 64f5edca2401f6c2f23564da9dd52e92d08b3a20 fixed the same hazard
on master; this is a backport, but the modulo operator does not exist
in older releases.

Michael Paquier

contrib/pgbench/pgbench.c

index 4e22695f8fd35f6b21bb4e697ac6428fd2985a38..062a32fa0f36dd47fb198634d550c51a0d564cd5 100644 (file)
 #ifndef INT64_MAX
 #define INT64_MAX  INT64CONST(0x7FFFFFFFFFFFFFFF)
 #endif
+#ifndef INT64_MIN
+#define INT64_MIN  (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1)
+#endif
+
 
 /*
  * Multi-platform pthread implementations
@@ -1331,13 +1335,37 @@ top:
                    snprintf(res, sizeof(res), INT64_FORMAT, ope1 * ope2);
                else if (strcmp(argv[3], "/") == 0)
                {
+                   int64   operes;
+
                    if (ope2 == 0)
                    {
                        fprintf(stderr, "%s: division by zero\n", argv[0]);
                        st->ecnt++;
                        return true;
                    }
-                   snprintf(res, sizeof(res), INT64_FORMAT, ope1 / ope2);
+                   /*
+                    * 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 (ope2 == -1)
+                   {
+                       operes = -ope1;
+
+                       /* overflow check (needed for INT64_MIN) */
+                       if (ope1 == INT64_MIN)
+                       {
+                           fprintf(stderr, "bigint out of range\n");
+                           st->ecnt++;
+                           return true;
+                       }
+                   }
+                   else
+                       operes = ope1 / ope2;
+                   snprintf(res, sizeof(res), INT64_FORMAT, operes);
                }
                else
                {