Merge remote-tracking branch 'origin/DivideByZeroProtection' into develop

This commit is contained in:
Jason Turner 2015-01-16 10:18:50 -07:00
commit bde4eb04b6
5 changed files with 58 additions and 15 deletions

View File

@ -396,10 +396,9 @@ namespace chaiscript
m->add(user_type<std::runtime_error>(), "runtime_error"); m->add(user_type<std::runtime_error>(), "runtime_error");
m->add(chaiscript::base_class<std::exception, std::runtime_error>()); m->add(chaiscript::base_class<std::exception, std::runtime_error>());
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error"); m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what"); m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object"); m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object"); m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
@ -487,7 +486,12 @@ namespace chaiscript
m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree"); m->add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree"); m->add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
m->add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>()); m->add(chaiscript::user_type<chaiscript::exception::eval_error>(), "eval_error");
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
m->add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
m->add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m); // chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);

View File

@ -22,6 +22,18 @@ namespace chaiscript {
class Type_Conversions; class Type_Conversions;
} // namespace chaiscript } // namespace chaiscript
namespace chaiscript
{
namespace exception
{
struct arithmetic_error : public std::runtime_error
{
arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {}
virtual ~arithmetic_error() CHAISCRIPT_NOEXCEPT {}
};
}
}
namespace chaiscript namespace chaiscript
{ {
@ -37,6 +49,21 @@ namespace chaiscript
class Boxed_Number class Boxed_Number
{ {
private: private:
template<typename T>
static void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
{
#ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO
if (t == 0) {
throw chaiscript::exception::arithmetic_error("divide by zero");
}
#endif
}
template<typename T>
static void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
{
}
struct boolean struct boolean
{ {
@ -61,7 +88,7 @@ namespace chaiscript
case Operators::not_equal: case Operators::not_equal:
return const_var(t != u); return const_var(t != u);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
}; };
@ -89,13 +116,14 @@ namespace chaiscript
t += u; t += u;
break; break;
case Operators::assign_quotient: case Operators::assign_quotient:
check_divide_by_zero(u);
t /= u; t /= u;
break; break;
case Operators::assign_difference: case Operators::assign_difference:
t -= u; t -= u;
break; break;
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
return t_lhs; return t_lhs;
@ -122,13 +150,14 @@ namespace chaiscript
t >>= u; t >>= u;
break; break;
case Operators::assign_remainder: case Operators::assign_remainder:
check_divide_by_zero(u);
t %= u; t %= u;
break; break;
case Operators::assign_bitwise_xor: case Operators::assign_bitwise_xor:
t ^= u; t ^= u;
break; break;
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
return t_lhs; return t_lhs;
} }
@ -146,6 +175,7 @@ namespace chaiscript
case Operators::shift_right: case Operators::shift_right:
return const_var(t >> u); return const_var(t >> u);
case Operators::remainder: case Operators::remainder:
check_divide_by_zero(u);
return const_var(t % u); return const_var(t % u);
case Operators::bitwise_and: case Operators::bitwise_and:
return const_var(t & u); return const_var(t & u);
@ -156,7 +186,7 @@ namespace chaiscript
case Operators::bitwise_complement: case Operators::bitwise_complement:
return const_var(~t); return const_var(~t);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
}; };
@ -171,6 +201,7 @@ namespace chaiscript
case Operators::sum: case Operators::sum:
return const_var(t + u); return const_var(t + u);
case Operators::quotient: case Operators::quotient:
check_divide_by_zero(u);
return const_var(t / u); return const_var(t / u);
case Operators::product: case Operators::product:
return const_var(t * u); return const_var(t * u);
@ -181,7 +212,7 @@ namespace chaiscript
case Operators::unary_plus: case Operators::unary_plus:
return const_var(+t); return const_var(+t);
default: default:
throw chaiscript::detail::exception::bad_any_cast(); throw chaiscript::detail::exception::bad_any_cast();
} }
} }
}; };
@ -327,7 +358,6 @@ namespace chaiscript
return oss.str(); return oss.str();
} }
public: public:
Boxed_Number() Boxed_Number()
: bv(Boxed_Value(0)) : bv(Boxed_Value(0))
@ -843,12 +873,12 @@ namespace chaiscript
struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number>
{ {
}; };
/// Cast_Helper for converting from Boxed_Value to Boxed_Number /// Cast_Helper for converting from Boxed_Value to Boxed_Number
template<> template<>
struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number>
{ {
}; };
} }
#ifdef CHAISCRIPT_MSVC #ifdef CHAISCRIPT_MSVC

View File

@ -93,6 +93,8 @@ namespace chaiscript
// If it's an arithmetic operation we want to short circuit dispatch // If it's an arithmetic operation we want to short circuit dispatch
try{ try{
return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs); return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
} catch (const chaiscript::exception::arithmetic_error &) {
throw;
} catch (...) { } catch (...) {
throw exception::eval_error("Error with numeric operator calling: " + t_oper_string); throw exception::eval_error("Error with numeric operator calling: " + t_oper_string);
} }

View File

@ -0,0 +1,9 @@
try {
3/0
assert_true(false); // should never get here
} catch (e) {
assert_equal("Arithmetic error: divide by zero", e.what())
}
assert_equal(3/0.0, Infinity)

View File

@ -1,6 +1,6 @@
var func = fun(){ var func = fun(){
var ret = 0; var ret = 0;
for (var i = 0; i < 1000000; ++i) { for (var i = 0; i < 50000; ++i) {
ret += i; ret += i;
} }
return ret; return ret;
@ -9,9 +9,7 @@ var func = fun(){
var fut1 := async(func); var fut1 := async(func);
var fut2 := async(func); var fut2 := async(func);
var fut3 := async(func);
var fut4 := async(func);
// simply executing without crashing is good enough for this test // simply executing without crashing is good enough for this test
print(" ${fut1.get()} ${fut2.get()} ${fut3.get()} ${fut4.get()}") print(" ${fut1.get()} ${fut2.get()} ")