Closed schwehr closed 4 years ago
I am not sure that this is something we can 'resolve' easily in the code. There are no guarantees about the size of the stack. This is purely compiler and os dependent. Even some arbitrary depth limit of 32 is not guaranteed to solve the problem (with the added downside that it will result in valid expressions to become unprintable, which is definitely a bug).
As far as I know, stack overflow errors are just a thing that can happen when using recursive functions. The only real solution would be to not use recursive functions and rewrite these functions using loops that use the heap. But is this really worth the effort? How problematic is the raising of a stack overflow error in case of malconstructed input?
In my situation, a stack overflow is something I can't allow processes to do. So I have to put a fix in and I'd rather it match what is in the upstream repository. A non-recursive solution isn't critical for the short term. Why not make a solution that will almost always allow the default build to print a bogus expression, but that I can easily override in my build? In my compiler settings, I can just add "-DCODA_MAX_RECURSION=64" (or whatever number works for my memory configuration) e.g.
#ifndef CODA_MAX_RECURSION
// May OOM or stack-overflow with this many levels of recursion
#define CODA_MAX_RECURSION 100000
#endif
and
static int print_expression(const coda_expression *expr, int (*print) (const char *, ...), int xml, int html,
int precedence, int depth)
{
if (depth > CODA_MAX_RECURSION) {
coda_set_error(CODA_ERROR_INVALID_FORMAT, "too many levels of recursion in expression");
return -1;
}
depth++;
Some of the reasons behind limiting the recursion:
cannot finish printing
error for most users in my experienceSee also this discussion which is similar:
https://github.com/nlohmann/json/issues/832#issuecomment-363192371
Ok. I understand the rationale.
The problem is that this is not just about the print_expression()
function. It also applies to the evaluation and delete functions for expressions.
So, if we want to limit the depth we should do this in the construction of the expression tree (i.e. somewhere within coda_expression_from_string
). I will have a go at this.
Implemented in 2cde1d8c64bf191627505a417a0922d913e3a58e
Verified
One possible solution is to modify
print_expression
to track depthWould become
And it would start with things like this:
The fuzzer:
testcase-4902997930278912.zip