-
Notifications
You must be signed in to change notification settings - Fork 217
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
Stricter jörmungandr binary encoders regarding integer overflow #487
Conversation
b71a503
to
91da4fb
Compare
91da4fb
to
d2f8138
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original idea is good, but its implementation needs revisions:
It will be sufficient and give us the same level of guarantees as this PR to use toEnum
instead of fromIntegral
for unsafe conversions. Conversions is unsafe when the codomain is smaller than the domain.
unless (length inputs < 256) $ | ||
fail "number of inputs must be lower than 256" | ||
unless (length outputs < 256) $ | ||
fail "number of outputs must be lower than 256" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of magic number, it'd be better to use maxBound @Word8
to show where this 256
comes from.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done:
unless (length inputs <= fromIntegral (maxBound :: Word8)) $
fail "number of inputs cannot be greater than 255"
maxBound :: Word8
is255
so I've used255]
instead of256)
as bound- Preserved the 255 in the message despite the risk of going out of sync
- Avoided to state the entire allowed range, e.g.
number of inputs must be within the range [0,255]
, since I believe the 0 is a grey-zone.
putWord8 $ fromIntegral $ length inputs | ||
putWord8 $ fromIntegral $ length outputs | ||
putWord8 $ overflowSafeCoerce $ length inputs | ||
putWord8 $ overflowSafeCoerce $ length outputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should either check the length with unless
or with overflowSafeCoerce
. Doing both is overkill.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Integer type promotions in the deserialisation (Get
) shouldn't be too much of a problem. (Unless there are values which cause us to allocate an excessively large amount of memory).
But it's good to add checks in the serialisation (Put
) before squeezing values into 8 bits - as you have done.
I am wondering what we should do about the error handling here. Should transactions with >= 255 inputs or outputs be rejected at the API level, or should we wait for serialisation to fail and return that error? I think the latter is OK, as long as it's clear to the user why the error happens.
We will most likely never create a transaction with more than 255 inputs, because of the way our CS work. So it's unlikely that such transaction would make it to being serialized. Having said that, I'd be more inclined to catch the erroneous transaction much earlier and avoid creating it in a first place. Failures in the Binary module should really be our last-resort / safety net; being the sign that something went wrong in the upper layers. |
c1ecfd0
to
aa8851a
Compare
New approach:
|
- Particulary in encoders (putX) - Somewhat for decoders (getX)
and add a test case for unbalanced transactions
aa8851a
to
b399323
Compare
Issue Number
#219
Overview
fromIntegral
withtoEnum
where it might overflow.Comments