-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Add static_assert to prevent VARINT(<signed value>) #9753
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
Conversation
|
Failed on OSX: |
If this is c++14 code, I wonder why the other builds succeeded, given that we are at c++11. |
|
Are the other systems using g++ > version 5? |
|
Do we explicitly request compilation for stdc++11? Would make sense to do so, as the default can (and has) changed. |
|
This is a weird one. g++ accepts Not much we can do about that, as far as I can tell. Nothing I tried made g++ complain about it. @laanwj I agree. It turned out to be unrelated to this issue, but I whipped up theuni@9829c54 anyway. Will PR it. @ryanofsky You can just use a struct with a constexpr ctor instead: template<VarIntMode Mode, typename I>
struct CheckVarIntMode
{
constexpr CheckVarIntMode() {
static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value, "Unsigned type required with mode DEFAULT.");
static_assert(Mode != VarIntMode::BROKEN_SIGNED || std::is_signed<I>::value, "Signed type required with mode BROKEN_SIGNED.");
}
}; |
Avoid constexpr void function, which is a C++14 feature. Change was suggested in bitcoin#9753 (comment)
dd094d6 to
d1df497
Compare
|
Thanks @theuni, that's a clever workaround. Added in dd094d6. Squashed dd094d6 -> d1df497 (varint-assert.1 -> varint-assert.2) |
d1df497 to
8950418
Compare
|
Rebased d1df497 -> 8950418 (pr/varint-assert.2 -> pr/varint-assert.3) because of conflict with renamed nVersion variable in #8808. |
|
Concept ACK. Though i'd prefer to just introduce a new macro rather than a default arg: |
|
This seems to be in limbo - @ryanofsky can you please reply to @theuni's comment? |
I guess I prefer the opposite. I think it's good if you can look at code like: and know that all 3 encodings of An interface like: just seems more opaque. The implementation would also be a little longer and more duplicative. |
8950418 to
46e649b
Compare
46e649b to
649bfb0
Compare
FWIW I don't like the repetition of VarInt here, the VarIntMode:: could be inside the macro instead of outside it to just have But I wouldn't mind explicit VARUINT_U and VARINT_I or even VARUINT and VARSINT either... |
|
@laanwj. Implemented your suggestion in af20ce5. Let me know if you think I should squash it. As mentioned before though, I prefer current change because VARINT() is a simple, dumb, single macro and regular VARINT(x) cases work exactly the same as before. The only verbose case is the VarIntMode::NONNEGATIVE_SIGNED one and IMO that is verbose in a good way, because if you are reading the code you can tell that VarIntMode::NONNEGATIVE_SIGNED is just a plain c++ value, not more macro magic goop, and you can click "VarIntMode" in your IDE to go to the definition of the enum, and see documentation and details about the encoding. |
|
Thanks.
I agree in general, but for this specific case this just seems overdone. |
|
Please let me know if af20ce5 is ok and does what you want then. I think both the implementation and the resulting interface are gross, but if this is actually what you want, I'll squash it. |
|
Still need feedback on whether to merge af20ce5 into this PR. I don't love the macro magic it adds, and I don't see much benefit in the change since only weird legacy code should ever need to use |
|
I would still prefer a separate macro, so that makes 3 differing opinions here :) |
Seperate macros was also one of my preferences, FWIW:
I just don't like the overly verbose construction of passing a scoped enum into everything. Edit: then again, I'm also not intending to hold this up indefinitely based on that, so utACK |
Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128. This commit changes the VARINT macro to trigger an error by default if called with an signed value, and updates broken uses of VARINT to pass a special flag that lets them keep working with no change in behavior.
649bfb0 to
499d95e
Compare
|
Rebased 8950418 -> 46e649b (pr/varint-assert.3 -> pr/varint-assert.4) due to conflict with #10195 |
|
utACK 499d95e |
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky) Pull request description: Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128. This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior. There is some discussion about this issue here: #9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration. Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky) Pull request description: Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128. This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior. There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration. Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky) Pull request description: Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128. This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior. There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration. Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
172fe15 Add missing locks and locking annotations for CAddrMan (practicalswift) 9271ace Support serialization as another type without casting (Pieter Wuille) dc37dd9 Remove unnecessary NONNEGATIVE_SIGNED (Russell Yanofsky) ddd2ab1 Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky) 539db35 Support deserializing into temporaries (Pieter Wuille) 36db7fd Merge READWRITEMANY into READWRITE (Pieter Wuille) 08ebd5b Remove old pre C++11 functions begin_ptr/end_ptr. (furszy) 9c84665 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Pull request description: Back ported some pretty concise PRs from upstream over the data serialization area. * bitcoin#9305. --> removal of pre c++11 compatibility functions. * bitcoin#9693. --> prevent integer overflow in `ReadVarInt`. * bitcoin#9753. --> compile error if VARINT is called with a signed value. * bitcoin#12683. --> fixing constness violations * bitcoin#12731. --> support for `READWRITEAS` macro. ACKs for top commit: random-zebra: ACK 172fe15 Fuzzbawls: ACK 172fe15 Tree-SHA512: 1e1e697761b885dcc1aed8a2132bed693b1c76f1f2ed22ae5c074dfb4c353b81d307f71a4c12ed71fc39fd2207c1403881bd699e32b85a167bee57b4f0946130
Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.
This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.
There is some discussion about this issue here: #9693 (comment). I think another good change along these lines would be to make
GetSizeOfVarIntandWriteVarIntthrow exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.