Originally surfaced in #14042 the problem, or at least my own summary of it, is that Cranelift-generated stack probes are an unaccounted for cost when it comes to fuel consumption. Cranelift's stack probes are used for large stack frames and the probe is either unrolled or codegen'd as a loop depending on the size of the stack frame. This cost is not account for in fuel consumption insofar as it's possible for a malicious guest to craft modules where the time/resources taken to execute are constant in fuel consumption but variable in wall-clock time and stack consumption.
One example from #14042 is a large function with thousands of locals which dynamically ends up doing nothing (e.g. early returns). In this situation if all these locals are live via a computation at the end, and if optimizations are disabled, then lots of locals are spilled to the stack. This causes a stack frame to be generated which is proportional to the number of locals but this function consumes a constant amount of fuel regardless of the number of locals.
Another example of increasing stack space, however, is having a very large operand stack in wasm. For example wasm can repeatedly call a function to return a value, and then after generating N values add them all up. This is another example of a variable-sized wasm function incurring a variable-sized amount of runtime (due to differing stack frame sizes) while consuming a constant amount of fuel at runtime.
The overall problem seems to be that the cost of the probe itself is unaccounted for meaning guests, in theory, given a fixed budget of fuel can consume an arbitrary amount of time. I'm not personally sure of the best fix for this since the size of the stack frame isn't known until the end of compilation. One nice property of fuel as well is that it's deterministic across targets within a Wasmtime version right now, but if the literal stack frame size were taken into account this would start to diverge across compiler options/targets/etc. On the other hand there are indicators of stack frame size, such as locals or operand-stack-depth, but I wouldn't be confident in saying these are the only variable sources of stack-frame-sizes.
Hence, an issue!
Originally surfaced in #14042 the problem, or at least my own summary of it, is that Cranelift-generated stack probes are an unaccounted for cost when it comes to fuel consumption. Cranelift's stack probes are used for large stack frames and the probe is either unrolled or codegen'd as a loop depending on the size of the stack frame. This cost is not account for in fuel consumption insofar as it's possible for a malicious guest to craft modules where the time/resources taken to execute are constant in fuel consumption but variable in wall-clock time and stack consumption.
One example from #14042 is a large function with thousands of locals which dynamically ends up doing nothing (e.g. early returns). In this situation if all these locals are live via a computation at the end, and if optimizations are disabled, then lots of locals are spilled to the stack. This causes a stack frame to be generated which is proportional to the number of locals but this function consumes a constant amount of fuel regardless of the number of locals.
Another example of increasing stack space, however, is having a very large operand stack in wasm. For example wasm can repeatedly call a function to return a value, and then after generating N values add them all up. This is another example of a variable-sized wasm function incurring a variable-sized amount of runtime (due to differing stack frame sizes) while consuming a constant amount of fuel at runtime.
The overall problem seems to be that the cost of the probe itself is unaccounted for meaning guests, in theory, given a fixed budget of fuel can consume an arbitrary amount of time. I'm not personally sure of the best fix for this since the size of the stack frame isn't known until the end of compilation. One nice property of fuel as well is that it's deterministic across targets within a Wasmtime version right now, but if the literal stack frame size were taken into account this would start to diverge across compiler options/targets/etc. On the other hand there are indicators of stack frame size, such as locals or operand-stack-depth, but I wouldn't be confident in saying these are the only variable sources of stack-frame-sizes.
Hence, an issue!