Bug 213383 - -Wsign-compare in isValidOptionSet
Summary: -Wsign-compare in isValidOptionSet
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Template Framework (show other bugs)
Version: WebKit Nightly Build
Hardware: PC Linux
: P2 Minor
Assignee: Michael Catanzaro
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-06-19 09:23 PDT by Michael Catanzaro
Modified: 2020-06-22 14:44 PDT (History)
8 users (show)

See Also:


Attachments
Patch (1.53 KB, patch)
2020-06-19 12:00 PDT, Michael Catanzaro
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Catanzaro 2020-06-19 09:23:00 PDT
Since r263208 "[IPC hardening] OptionSet<> values should be validated":

[4332/4574] Building CXX object Source...ources/UnifiedSource-50d0d8dd-14.cpp.o
In file included from /home/mcatanzaro/Projects/WebKit/Source/WebKit/Shared/glib/InputMethodState.h:31,
                 from /home/mcatanzaro/Projects/WebKit/Source/WebKit/Shared/glib/InputMethodState.cpp:27,
                 from DerivedSources/WebKit/unified-sources/UnifiedSource-50d0d8dd-14.cpp:1:
DerivedSources/ForwardingHeaders/wtf/OptionSet.h: In instantiation of ‘constexpr bool WTF::isValidOptionSet(WTF::OptionSet<E>) [with E = WebKit::InputMethodState::Hint]’:
/home/mcatanzaro/Projects/WebKit/Source/WebKit/Platform/IPC/ArgumentCoders.h:69:35:   required from ‘static bool IPC::ArgumentCoder<WTF::OptionSet<E> >::decode(IPC::Decoder&, WTF::OptionSet<E>&) [with T = WebKit::InputMethodState::Hint]’
/home/mcatanzaro/Projects/WebKit/Source/WebKit/Platform/IPC/ArgumentCoder.h:72:41:   required by substitution of ‘template<class T> static uint8_t IPC::UsesLegacyDecoder<WTF::OptionSet<WebKit::InputMethodState::Hint> >::checkArgumentCoder<T>(IPC::UsesLegacyDecoder<WTF::OptionSet<WebKit::InputMethodState::Hint> >::Helper<bool (*)(IPC::Decoder&, WTF::OptionSet<WebKit::InputMethodState::Hint>&), (& IPC::ArgumentCoder<T>::decode)>*) [with T = WTF::OptionSet<WebKit::InputMethodState::Hint>]’
/home/mcatanzaro/Projects/WebKit/Source/WebKit/Platform/IPC/ArgumentCoder.h:76:85:   required from ‘constexpr const bool IPC::UsesLegacyDecoder<WTF::OptionSet<WebKit::InputMethodState::Hint> >::value’
/home/mcatanzaro/Projects/WebKit/Source/WebKit/Platform/IPC/Decoder.h:140:126:   required by substitution of ‘template<class T, std::enable_if_t<(((! std::is_enum<_Tp>::value) && (! std::is_arithmetic<_Tp>::value)) && (! IPC::UsesLegacyDecoder<U>::value))>* <anonymous> > bool IPC::Decoder::decode(T&) [with T = WTF::OptionSet<WebKit::InputMethodState::Hint>; std::enable_if_t<(((! std::is_enum<_Tp>::value) && (! std::is_arithmetic<_Tp>::value)) && (! IPC::UsesLegacyDecoder<U>::value))>* <anonymous> = <missing>]’
/home/mcatanzaro/Projects/WebKit/Source/WebKit/Shared/glib/InputMethodState.cpp:117:36:   required from here
DerivedSources/ForwardingHeaders/wtf/OptionSet.h:257:52: warning: comparison of integer expressions of different signedness: ‘WTF::OptionSet<WebKit::InputMethodState::Hint>::StorageType’ {aka ‘unsigned int’} and ‘int’ [-Wsign-compare]
  257 |     return (optionSet.toRaw() | allValidBitsValue) == allValidBitsValue;
      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
Comment 1 Michael Catanzaro 2020-06-19 09:35:11 PDT
Since this is a bitwise comparison, and we don't normally want to use signed types for bitwise comparisons, we probably want to cast allValidBitsValue on the right side of the expression to unsigned. I think that can be done using std::make_unsigned. Testing this....
Comment 2 Michael Catanzaro 2020-06-19 10:46:26 PDT
So that does work, but I'm going to try to mandate use of unsigned type instead. Using signed types with OptionSet is probably a mistake.
Comment 3 Michael Catanzaro 2020-06-19 11:21:11 PDT
(In reply to Michael Catanzaro from comment #2)
> So that does work, but I'm going to try to mandate use of unsigned type
> instead. Using signed types with OptionSet is probably a mistake.

So that was a bad idea, because OptionSet goes out of its way to allow this:

using StorageType = std::make_unsigned_t<std::underlying_type_t<E>>;

I think isValidOptionSet should do the same. Let me try that.
Comment 4 Michael Catanzaro 2020-06-19 11:57:40 PDT
OK, I present two... options. ;)

Option #1: OptionSetValueChecker should match the OptionSet's StorageType, which is std::make_unsigned_t<std::underlying_type_t<E>>, instead of directly using std::underlying_type_t<E>:

diff --git a/Source/WTF/wtf/OptionSet.h b/Source/WTF/wtf/OptionSet.h
index de111b16b355..8450b1a240d9 100644
--- a/Source/WTF/wtf/OptionSet.h
+++ b/Source/WTF/wtf/OptionSet.h
@@ -253,8 +253,8 @@ private:
 template<typename E>
 WARN_UNUSED_RETURN constexpr bool isValidOptionSet(OptionSet<E> optionSet)
 {
-    auto allValidBitsValue = OptionSetValueChecker<std::underlying_type_t<E>, typename EnumTraits<E>::values>::allValidBits();
-    return (optionSet.toRaw() | allValidBitsValue) == allValidBitsValue;
+    auto allValidBitsValue = OptionSetValueChecker<std::make_unsigned_t<std::underlying_type_t<E>>, typename EnumTraits<E>::values>::allValidBits();
+    return (optionSet.toRaw() | allValidBitsValue) == std::underlying_type_t<E>(allValidBitsValue);
 }

That fixes the warning without making any changes in other files. I'll attach this patch for review.

Option #2: we could require the OptionSet to use an unsigned underlying value to call isValidOptionSet using std::enable_if. That would enforce unsigned underlying value only for OptionSets that are validated by isValidOptionSet. We only have to change the underlying type of WebKit::InputMethodState::Hint in Source/WebKit/Shared/glib/InputMethodState.h. I decided against making this my preferred option because valid OptionSets do not actually have to use unsigned underlying storage, so it would be a bit weird to require that to call isValidOptionSet, but this would be useful if we want to enforce this for types sent over IPC. (Do we want to enforce it for types sent over IPC?)

Option #3: would be to prohibit OptionSet from ever using signed underlying value, but that's going to require changing a lot of enums. Doesn't seem worth it, so I don't propose this.
Comment 5 Michael Catanzaro 2020-06-19 12:00:07 PDT
(In reply to Michael Catanzaro from comment #4)
> +    return (optionSet.toRaw() | allValidBitsValue) ==
> std::underlying_type_t<E>(allValidBitsValue);

That's a Ctrl+Z mistake, I'll attach a patch that actually works.
Comment 6 Michael Catanzaro 2020-06-19 12:00:23 PDT
Created attachment 402301 [details]
Patch
Comment 7 Michael Catanzaro 2020-06-19 12:06:48 PDT
(In reply to Michael Catanzaro from comment #4)
> this would be useful if we want to enforce this
> for types sent over IPC. (Do we want to enforce it for types sent over IPC?)

Maybe we do? r263208 ensured this for all types used in cross-platform code. If it's important, r- my patch and I'll upload a version that enforces this. The downside is that it would no longer be possible to call isValidOptionSet on valid OptionSets that use signed underlying storage, which would be weird.
Comment 8 EWS 2020-06-19 12:52:27 PDT
Committed r263280: <https://trac.webkit.org/changeset/263280>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 402301 [details].
Comment 9 Radar WebKit Bug Importer 2020-06-19 12:53:19 PDT
<rdar://problem/64541629>
Comment 10 David Kilzer (:ddkilzer) 2020-06-22 14:44:07 PDT
Thanks Michael!