[Groonga-commit] groonga/groonga at 2b99327 [master] Fix a bug that a division overflow causes a fatal error

Back to archive index

susumu.yata null+****@clear*****
Fri Feb 7 18:37:48 JST 2014


susumu.yata	2014-02-07 18:37:48 +0900 (Fri, 07 Feb 2014)

  New Revision: 2b99327acb7771d3bc1c2eed09e71cda3d58d4b0
  https://github.com/groonga/groonga/commit/2b99327acb7771d3bc1c2eed09e71cda3d58d4b0

  Message:
    Fix a bug that a division overflow causes a fatal error
    
    Redmine: fixes #2307

  Modified files:
    lib/expr.c

  Modified: lib/expr.c (+280 -20)
===================================================================
--- lib/expr.c    2014-02-07 11:24:21 +0900 (831d5ec)
+++ lib/expr.c    2014-02-07 18:37:48 +0900 (f331958)
@@ -2233,6 +2233,276 @@ grn_proc_call(grn_ctx *ctx, grn_obj *proc, int nargs, grn_obj *caller)
   }                                                                     \
 } while (0)
 
+#define SIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y)                   \
+  ((y == -1) ? -(x) : (x) / (y))
+#define UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) ((x) / (y))
+#define FLOAT_DIVISION_OPERATION_SLASH(x, y) ((double)(x) / (double)(y))
+#define SIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((y == -1) ? 0 : (x) / (y))
+#define UNSIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((x) % (y))
+#define FLOAT_DIVISION_OPERATION_MOD(x, y) (fmod((x), (y)))
+
+#define DIVISION_OPERATION_DISPATCH_RIGHT(set, get, x_, y, res,         \
+                                          signed_integer_operation,     \
+                                          unsigned_integer_operation,   \
+                                          float_operation) do {         \
+  switch (y->header.domain) {                                           \
+  case GRN_DB_INT8 :                                                    \
+    {                                                                   \
+      int y_;                                                           \
+      y_ = GRN_INT8_VALUE(y);                                           \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT8 :                                                   \
+    {                                                                   \
+      int y_;                                                           \
+      y_ = GRN_UINT8_VALUE(y);                                          \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_INT16 :                                                   \
+    {                                                                   \
+      int y_;                                                           \
+      y_ = GRN_INT16_VALUE(y);                                          \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT16 :                                                  \
+    {                                                                   \
+      int y_;                                                           \
+      y_ = GRN_UINT16_VALUE(y);                                         \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_INT32 :                                                   \
+    {                                                                   \
+      int y_;                                                           \
+      y_ = GRN_INT32_VALUE(y);                                          \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT32 :                                                  \
+    {                                                                   \
+      unsigned int y_;                                                  \
+      y_ = GRN_UINT32_VALUE(y);                                         \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, unsigned_integer_operation(x_, y_));                \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_TIME :                                                    \
+    {                                                                   \
+      long long int y_;                                                 \
+      y_ = GRN_TIME_VALUE(y);                                           \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_INT64 :                                                   \
+    {                                                                   \
+      long long int y_;                                                 \
+      y_ = GRN_INT64_VALUE(y);                                          \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, signed_integer_operation(x_, y_));                  \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT64 :                                                  \
+    {                                                                   \
+      long long unsigned int y_;                                        \
+      y_ = GRN_UINT64_VALUE(y);                                         \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      set(ctx, res, unsigned_integer_operation(x_, y_));                \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_FLOAT :                                                   \
+    {                                                                   \
+      double y_;                                                        \
+      y_ = GRN_FLOAT_VALUE(y);                                          \
+      ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_);                     \
+      res->header.domain = GRN_DB_FLOAT;                                \
+      GRN_FLOAT_SET(ctx, res, float_operation(x_, y_));                 \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_SHORT_TEXT :                                              \
+  case GRN_DB_TEXT :                                                    \
+  case GRN_DB_LONG_TEXT :                                               \
+    set(ctx, res, 0);                                                   \
+    if (grn_obj_cast(ctx, y, res, GRN_FALSE)) {                         \
+      ERR(GRN_INVALID_ARGUMENT,                                         \
+          "not a numerical format: <%.*s>",                             \
+          (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y));                     \
+      goto exit;                                                        \
+    }                                                                   \
+    /* The following "+ 0" is needed to suppress warnings that say */   \
+    /* comparison is always false due to limited range of data type */  \
+    set(ctx, res, signed_integer_operation(x_, (get(res) + 0)));        \
+    break;                                                              \
+  default :                                                             \
+    break;                                                              \
+  }                                                                     \
+} while (0)
+
+#define DIVISION_OPERATION_DISPATCH_LEFT(x, y, res,                     \
+                                         signed_integer_operation,      \
+                                         unsigned_integer_operation,    \
+                                         float_operation,               \
+                                         invalid_type_error) do {       \
+  switch (x->header.domain) {                                           \
+  case GRN_DB_INT8 :                                                    \
+    {                                                                   \
+      int x_;                                                           \
+      x_ = GRN_INT8_VALUE(x);                                           \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT8_SET,                   \
+                                        GRN_INT8_VALUE,                 \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT8 :                                                   \
+    {                                                                   \
+      int x_;                                                           \
+      x_ = GRN_UINT8_VALUE(x);                                          \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT8_SET,                  \
+                                        (int)GRN_UINT8_VALUE,           \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_INT16 :                                                   \
+    {                                                                   \
+      int x_;                                                           \
+      x_ = GRN_INT16_VALUE(x);                                          \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT16_SET,                  \
+                                        GRN_INT16_VALUE,                \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT16 :                                                  \
+    {                                                                   \
+      int x_;                                                           \
+      x_ = GRN_UINT16_VALUE(x);                                         \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT16_SET,                 \
+                                        (int)GRN_UINT16_VALUE,          \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_INT32 :                                                   \
+    {                                                                   \
+      int x_;                                                           \
+      x_ = GRN_INT32_VALUE(x);                                          \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT32_SET,                  \
+                                        GRN_INT32_VALUE,                \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT32 :                                                  \
+    {                                                                   \
+      unsigned int x_;                                                  \
+      x_ = GRN_UINT32_VALUE(x);                                         \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT32_SET,                 \
+                                        GRN_UINT32_VALUE,               \
+                                        x_, y, res,                     \
+                                        unsigned_integer_operation,     \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_INT64 :                                                   \
+    {                                                                   \
+      long long int x_;                                                 \
+      x_ = GRN_INT64_VALUE(x);                                          \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT64_SET,                  \
+                                        GRN_INT64_VALUE,                \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_TIME :                                                    \
+    {                                                                   \
+      long long int x_;                                                 \
+      x_ = GRN_TIME_VALUE(x);                                           \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_TIME_SET,                   \
+                                        GRN_TIME_VALUE,                 \
+                                        x_, y, res,                     \
+                                        signed_integer_operation,       \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_UINT64 :                                                  \
+    {                                                                   \
+      long long unsigned int x_;                                        \
+      x_ = GRN_UINT64_VALUE(x);                                         \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT64_SET,                 \
+                                        GRN_UINT64_VALUE,               \
+                                        x_, y, res,                     \
+                                        unsigned_integer_operation,     \
+                                        unsigned_integer_operation,     \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_FLOAT :                                                   \
+    {                                                                   \
+      double x_;                                                        \
+      x_ = GRN_FLOAT_VALUE(x);                                          \
+      DIVISION_OPERATION_DISPATCH_RIGHT(GRN_FLOAT_SET,                  \
+                                        GRN_FLOAT_VALUE,                \
+                                        x_, y, res,                     \
+                                        float_operation,                \
+                                        float_operation,                \
+                                        float_operation);               \
+    }                                                                   \
+    break;                                                              \
+  case GRN_DB_SHORT_TEXT :                                              \
+  case GRN_DB_TEXT :                                                    \
+  case GRN_DB_LONG_TEXT :                                               \
+    invalid_type_error;                                                 \
+    break;                                                              \
+  default:                                                              \
+    break;                                                              \
+  }                                                                     \
+  code++;                                                               \
+} while (0)
+
+#define DIVISION_OPERATION_DISPATCH(signed_integer_operation,           \
+                                    unsigned_integer_operation,         \
+                                    float_operation,                    \
+                                    invalid_type_error) do {            \
+  grn_obj *x, *y;                                                       \
+                                                                        \
+  POP2ALLOC1(x, y, res);                                                \
+  if (y != res) {                                                       \
+    res->header.domain = x->header.domain;                              \
+  }                                                                     \
+  DIVISION_OPERATION_DISPATCH_LEFT(x, y, res,                           \
+                                   signed_integer_operation,            \
+                                   unsigned_integer_operation,          \
+                                   float_operation,                     \
+                                   invalid_type_error);                 \
+  if (y == res) {                                                       \
+    res->header.domain = x->header.domain;                              \
+  }                                                                     \
+} while (0)
+
 #define ARITHMETIC_UNARY_OPERATION_DISPATCH(integer_operation,          \
                                             float_operation,            \
                                             left_expression_check,      \
@@ -3584,38 +3854,28 @@ grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs)
           ,);
         break;
       case GRN_OP_SLASH :
-        ARITHMETIC_BINARY_OPERATION_DISPATCH(
-          INTEGER_ARITHMETIC_OPERATION_SLASH,
-          INTEGER_ARITHMETIC_OPERATION_SLASH,
-          INTEGER_ARITHMETIC_OPERATION_SLASH,
-          INTEGER_ARITHMETIC_OPERATION_SLASH,
-          FLOAT_ARITHMETIC_OPERATION_SLASH,
-          ARITHMETIC_OPERATION_NO_CHECK,
-          ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK,
+        DIVISION_OPERATION_DISPATCH(
+          SIGNED_INTEGER_DIVISION_OPERATION_SLASH,
+          UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH,
+          FLOAT_DIVISION_OPERATION_SLASH,
           {
             ERR(GRN_INVALID_ARGUMENT,
                 "\"string\" / \"string\" "
                 "isn't supported");
             goto exit;
-          }
-          ,);
+          });
         break;
       case GRN_OP_MOD :
-        ARITHMETIC_BINARY_OPERATION_DISPATCH(
-          INTEGER_ARITHMETIC_OPERATION_MOD,
-          INTEGER_ARITHMETIC_OPERATION_MOD,
-          INTEGER_ARITHMETIC_OPERATION_MOD,
-          INTEGER_ARITHMETIC_OPERATION_MOD,
-          FLOAT_ARITHMETIC_OPERATION_MOD,
-          ARITHMETIC_OPERATION_NO_CHECK,
-          ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK,
+        DIVISION_OPERATION_DISPATCH(
+          SIGNED_INTEGER_DIVISION_OPERATION_MOD,
+          UNSIGNED_INTEGER_DIVISION_OPERATION_MOD,
+          FLOAT_DIVISION_OPERATION_MOD,
           {
             ERR(GRN_INVALID_ARGUMENT,
                 "\"string\" %% \"string\" "
                 "isn't supported");
             goto exit;
-          }
-          ,);
+          });
         break;
       case GRN_OP_BITWISE_NOT :
         ARITHMETIC_UNARY_OPERATION_DISPATCH(
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index