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

@ -397,7 +397,6 @@ namespace chaiscript
m->add(user_type<std::runtime_error>(), "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(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
@ -487,7 +486,12 @@ namespace chaiscript
m->add(chaiscript::fun(&has_parse_tree), "has_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);

View File

@ -22,6 +22,18 @@ namespace chaiscript {
class Type_Conversions;
} // 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
{
@ -37,6 +49,21 @@ namespace chaiscript
class Boxed_Number
{
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
{
@ -89,6 +116,7 @@ namespace chaiscript
t += u;
break;
case Operators::assign_quotient:
check_divide_by_zero(u);
t /= u;
break;
case Operators::assign_difference:
@ -122,6 +150,7 @@ namespace chaiscript
t >>= u;
break;
case Operators::assign_remainder:
check_divide_by_zero(u);
t %= u;
break;
case Operators::assign_bitwise_xor:
@ -146,6 +175,7 @@ namespace chaiscript
case Operators::shift_right:
return const_var(t >> u);
case Operators::remainder:
check_divide_by_zero(u);
return const_var(t % u);
case Operators::bitwise_and:
return const_var(t & u);
@ -171,6 +201,7 @@ namespace chaiscript
case Operators::sum:
return const_var(t + u);
case Operators::quotient:
check_divide_by_zero(u);
return const_var(t / u);
case Operators::product:
return const_var(t * u);
@ -327,7 +358,6 @@ namespace chaiscript
return oss.str();
}
public:
Boxed_Number()
: bv(Boxed_Value(0))

View File

@ -93,6 +93,8 @@ namespace chaiscript
// If it's an arithmetic operation we want to short circuit dispatch
try{
return Boxed_Number::do_oper(t_oper, t_lhs, t_rhs);
} catch (const chaiscript::exception::arithmetic_error &) {
throw;
} catch (...) {
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 ret = 0;
for (var i = 0; i < 1000000; ++i) {
for (var i = 0; i < 50000; ++i) {
ret += i;
}
return ret;
@ -9,9 +9,7 @@ var func = fun(){
var fut1 := async(func);
var fut2 := async(func);
var fut3 := async(func);
var fut4 := async(func);
// simply executing without crashing is good enough for this test
print(" ${fut1.get()} ${fut2.get()} ${fut3.get()} ${fut4.get()}")
print(" ${fut1.get()} ${fut2.get()} ")