[math] Check for runtime errors

When number is infinite, not a number, larger than LONG_MAX or smaller
than LONG_MIN, print a corresponding error and return STATUS_CMD_ERROR.

This should fix the worst of the problems, by at least making them clear.

Fixes #4479.
Fixes #4768.
This commit is contained in:
Fabian Homborg 2018-03-07 18:01:12 +01:00
parent 98d29b53de
commit 9fc3d1215b
2 changed files with 24 additions and 2 deletions

View file

@ -17,7 +17,7 @@ The following options are available:
\subsection return-values Return Values
If the expression is successfully evaluated the return `status` is zero (success) else one.
If the expression is successfully evaluated and doesn't over/underflow or return NaN the return `status` is zero (success) else one.
\subsection math-syntax

View file

@ -5,6 +5,7 @@
#include <stddef.h>
#include <algorithm>
#include <cmath>
#include <string>
#include "tinyexpr.h"
@ -145,7 +146,28 @@ static int evaluate_expression(const wchar_t *cmd, parser_t &parser, io_streams_
double v = te_interp(narrow_str.c_str(), &error);
if (error.position == 0) {
if (opts.scale == 0) {
// Check some runtime errors after the fact.
// TODO: Really, this should be done in tinyexpr
// (e.g. infinite is the result of "x / 0"),
// but that's much more work.
if (std::isinfinite(v)) {
streams.err.append_format(L"%ls: Error: Result is infinite\n", cmd);
streams.err.append_format(L"'%ls'\n", expression.c_str());
retval = STATUS_CMD_ERROR;
} else if (std::isnan(v)) {
streams.err.append_format(L"%ls: Error: Result is not a number\n", cmd);
streams.err.append_format(L"'%ls'\n", expression.c_str());
retval = STATUS_CMD_ERROR;
} else if (v >= LONG_MAX) {
streams.err.append_format(L"%ls: Error: Result is too large\n", cmd);
streams.err.append_format(L"'%ls'\n", expression.c_str());
retval = STATUS_CMD_ERROR;
} else if (v <= LONG_MIN) {
streams.err.append_format(L"%ls: Error: Result is too small\n", cmd);
streams.err.append_format(L"'%ls'\n", expression.c_str());
retval = STATUS_CMD_ERROR;
} else if (opts.scale == 0) {
// Normal results
streams.out.append_format(L"%ld\n", static_cast<long>(v));
} else {
streams.out.append_format(L"%.*lf\n", opts.scale, v);