Telegram Open Network

The bug in comparison functions

V1037 Two or more case-branches perform the same actions. Check lines: 639, 645 builtins.cpp 639

int compute_compare(const VarDescr& x, const VarDescr& y, int mode) {
  switch (mode) {
    case 1:  // >
      return x.always_greater(y) ? 1 : (x.always_leq(y) ? 2 : 3);
    case 2:  // =
      return x.always_equal(y) ? 1 : (x.always_neq(y) ? 2 : 3);
    case 3:  // >=
      return x.always_geq(y) ? 1 : (x.always_less(y) ? 2 : 3);
    case 4:  // <
      return x.always_less(y) ? 1 : (x.always_geq(y) ? 2 : 3);
    case 5:  // <>
      return x.always_neq(y) ? 1 : (x.always_equal(y) ? 2 : 3);
    case 6:  // >=
      return x.always_geq(y) ? 1 : (x.always_less(y) ? 2 : 3);
    case 7:  // <=>
      return x.always_less(y)
                 ? 1
                 : (x.always_equal(y)
                        ? 2
                        : (x.always_greater(y)
                               ? 4
                               : (x.always_leq(y)
                                      ? 3
                                      : (x.always_geq(y)
                                            ? 6
                                            : (x.always_neq(y) ? 5 : 7)))));
    default:
      return 7;
  }
}

If you read carefully, you noticed that this code lacks a <= operation. Indeed, it is this operation that case 6 should be dealing with. We can deduce that by looking at two spots. The first is the initialization code:

AsmOp compile_cmp_int(std::vector<VarDescr>& res, std::vector<VarDescr>& args,
                      int mode) {
  ....
  if (x.is_int_const() && y.is_int_const()) {
    r.set_const(compute_compare(x.int_const, y.int_const, mode));
    x.unused();
    y.unused();
    return push_const(r.int_const);
  }
  int v = compute_compare(x, y, mode);
  ....
}

void define_builtins() {
  ....
  define_builtin_func("_==_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 2));
  define_builtin_func("_!=_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 5));
  define_builtin_func("_<_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 4));
  define_builtin_func("_>_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 1));
  define_builtin_func("_<=_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 6));
  define_builtin_func("_>=_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 3));
  define_builtin_func("_<=>_", arith_bin_op,
                      std::bind(compile_cmp_int, _1, _2, 7));
  ....
}

The define_builtins function, as you can see, contains a call compile_cmp_int for the <= operator with the mode parameter set to 6.
The second spot is the compile_cmp_int function itself, which lists the names of operations:

AsmOp compile_cmp_int(std::vector& res, std::vector& args,
                      int mode) {
  ....
  static const char* cmp_names[] = {"", "GREATER", "EQUAL", "GEQ", "LESS",
                                    "NEQ", "LEQ", "CMP"};
  ....
  return exec_op(cmp_names[mode], 2);
}

Index 6 corresponds to the LEQ word, which means “Less or Equal”.

Please click here to see more bugs from this project.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.