Throw instead of trapping on modulo by zero (#347)

Op::Modulo was the only arithmetic operator in the switch without a
zero-divisor guard, so {{ a % b }} raised SIGFPE and aborted the host
process. Op::Division already throws at renderer.hpp:307 and
Op::DivisibleBy already checks at :359. Guard the converted divisor,
which is what DivisibleBy does, so a fractional divisor that truncates
to zero is caught too.
This commit is contained in:
KBS
2026-09-10 08:03:56 +02:00
committed by GitHub
parent f89061f53f
commit 446379d2ba
3 changed files with 14 additions and 2 deletions
+5 -1
View File
@@ -321,7 +321,11 @@ class Renderer : public NodeVisitor {
} break;
case Op::Modulo: {
const auto args = get_arguments<2>(node);
make_result(args[0]->get<const json::number_integer_t>() % args[1]->get<const json::number_integer_t>());
const auto divisor = args[1]->get<const json::number_integer_t>();
if (divisor == 0) {
throw_renderer_error("modulo by zero", node);
}
make_result(args[0]->get<const json::number_integer_t>() % divisor);
} break;
case Op::AtId: {
const auto container = get_arguments<1, 0, false>(node)[0];
+5 -1
View File
@@ -2479,7 +2479,11 @@ class Renderer : public NodeVisitor {
} break;
case Op::Modulo: {
const auto args = get_arguments<2>(node);
make_result(args[0]->get<const json::number_integer_t>() % args[1]->get<const json::number_integer_t>());
const auto divisor = args[1]->get<const json::number_integer_t>();
if (divisor == 0) {
throw_renderer_error("modulo by zero", node);
}
make_result(args[0]->get<const json::number_integer_t>() % divisor);
} break;
case Op::AtId: {
const auto container = get_arguments<1, 0, false>(node)[0];
+4
View File
@@ -36,11 +36,15 @@ TEST_CASE("functions") {
CHECK(env.render("{{ 1 + 1 * 3 }}", data) == "4");
CHECK(env.render("{{ (1 + 1) * 3 }}", data) == "6");
CHECK(env.render("{{ 5 / 2 }}", data) == "2.5");
CHECK(env.render("{{ 5 % 2 }}", data) == "1");
CHECK(env.render("{{ 7 % -2 }}", data) == "1");
CHECK(env.render("{{ 5^3 }}", data) == "125");
CHECK(env.render("{{ 5 + 12 + 4 * (4 - (1 + 1))^2 - 75 * 1 }}", data) == "-42");
CHECK_THROWS_WITH(env.render("{{ +1 }}", data), "[inja.exception.parser_error] (at 1:7) too few arguments");
CHECK_THROWS_WITH(env.render("{{ 1 + }}", data), "[inja.exception.parser_error] (at 1:8) too few arguments");
CHECK_THROWS_WITH(env.render("{{ 5 % 0 }}", data), "[inja.exception.render_error] (at 1:6) modulo by zero");
CHECK_THROWS_WITH(env.render("{{ 5 % 0.5 }}", data), "[inja.exception.render_error] (at 1:6) modulo by zero");
}
SUBCASE("upper") {