-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decoder suppresses stack overflow #9
Comments
The issue seems to be a bit more general. Likely there is a -- This is a single byte (00000001)
byte = E.unsignedInt8 1
todoDecoder =
D.map (\_ -> Debug.todo "crash!") D.unsignedInt8
-- result == Nothing, instead of throwing the exception
result =
D.decode todoDecoder (E.encode ( byte)) |
The root thing is that any time you run a decoder, it may be trying to access bytes that do not exist. ExampleYou want to read an The implementation is eventually going to call ProblemSo if we want to avoid this exception, we need to introduce a bounds check in the JS code before calling any function like So I'm not really sure what the right move is here. The performance degredation needed to resolve this issue seems like a bad trade though. ConclusionI think it would be worthwhile for someone to do some performance experimentation here. I did not focus on that too much in the initial implementation, and I suspect it's possible to do better. In the course of those experiments, the experimenter may find a way to make things faster that also resolves this issue. Whatever the case, please share any results on this topic on https://discourse.elm-lang.org/ |
I made a micro-benchmark to check two bounds-checking strategies: if-statement to check the bound up-front, and a try/catch that catches the out of bounds RangeError. See the discourse post for more info. To summarize
So the try/catch approach seems the way to go. In practice that would mean that var _Bytes_read_i8 = F2(function( bytes, offset) { return __Utils_Tuple2(offset + 1, bytes.getInt8(offset)); }); Becomes var _Bytes_read_i8 = F2(function( bytes, offset) {
try {
return __Utils_Tuple2(offset + 1, bytes.getInt8(offset));
} catch (e) {
return __Utils_Tuple2(-1, 0));
}
}); Here I assume that Currently the Does this make sense? are there other paths to explore? |
Nice work @folkertdev! Rather than adding a |
Based on the spec, I don't think there is any guarantee that there is a consistent value that separates out-of-bounds access RangeErrors from other RangeErrors. All getters are based on GetViewValue which stipulates
So it is just a normal RangeError. In practice I found that none of the exception attributes are unique and consistent. For instance chrome will error with the message
and FF gives
Note that chrome capitalizes the initial So matching on the exception message looks quite brittle. Maybe all major JS engines give a similar message (can't test edge/IE at the moment) but there is no guarantee that they do (and the error in theory could change at any moment). Code to test this in other browsers: var buffer = new ArrayBuffer(8);
var view = new DataView(buffer);
view.setInt32(0, 42);
view.setInt32(4, 84);
view.getInt32(5); |
Change the image file decoding to support larger images. When using the previous version on a BMP image generated from `2019-06-26.eve-online-screenshot.jpeg`, it failed with this error: > Stopped with result: Failed to decode image: Failed to decode pixel array This problem correlated with the size of the image; when the image has too many pixels, the bytes decoding part (in the previous version) ran into a stack overflow. `Bytes.Decode` in turn has the problem that it hides the exception by decoding to `Nothing` instead. This problem in `Bytes.Decode` has also been reported at elm/bytes#9
A decoder I wrote returned
Nothing
for large byte sequences, but it was due to a stack overflow in a Bytes.Decode.map function I used.Here's a simple example:
The text was updated successfully, but these errors were encountered: