RFR: 8314258: checked_cast doesn't properly check some cases

Dean Long dlong at openjdk.org
Mon Oct 16 01:29:38 UTC 2023


On Mon, 2 Oct 2023 03:10:29 GMT, Kim Barrett <kbarrett at openjdk.org> wrote:

> Please review this improvement to the `checked_cast` utility.
> 
> checked_cast was added by JDK-8255544 to permit silencing of certain compiler
> warnings (such as from gcc's -Wconversion) for narrowing conversions when the
> value is "known" to be safely convertible.  It provides debug-only runtime
> verification that the conversion preserves the value while changing the type.
> 
> There has been a recent effort to apply checked_cast to eliminate -Wconversion
> warnings, with the eventual goal of turning on such warnings by default - see
> JDK-8135181.
> 
> The existing implementation checks that the value is unchanged by a round-trip
> conversion, and has no restrictions on the arguments.  There are several
> problems with this.
> 
> (1) There are some cases where conversion of an integral value to a different
> integral type may pass the check, even though the value isn't in the range of
> the destination type.
> 
> (2) Floating point to integral conversions are often intended to discard the
> fractional part.  But that won't pass the round-trip conversion test, making
> checked_cast mostly useless for such conversions.
> 
> (3) Integral to floating point conversions are often intended to be
> indifferent to loss of precision.  But again, that won't pass the round-trip
> conversion test, making checked_cast mostly useless for such conversions.
> 
> This change to checked_cast supports integral to integral conversions, but not
> conversions involving floating point types.  The intent is that we'll use
> "-Wconversion -Wno-float-conversion" instead of -Wconversion alone.  If/when
> we later want to enable -Wfloat-conversion, we can either extend checked_cast
> for that purpose, or probably better, add new functions tailored for the
> various use-cases.
> 
> It also supports enum to integral conversions, mostly for compatibility with
> old code that uses class-scoped enums instead of class-scoped static const
> integral members, to work around ancient broken compilers.  We still have a
> lot of such code.
> 
> This new checked_cast ensures (in debugging builds) that the value being
> converted is in the range of the destination type.  It does so while avoiding
> tautological comparisons, as some versions of some compilers may warn about
> such.  Note that this means it can also be used to suppress -Wsign-conversion
> warnings (which are not included in -Wconversion when compiling C++), which we
> might explore enabling in the future.
> 
> It also verifies a runtime check is needed, producing a compile-time error if
> not.  Unnecessary checked_cast...

src/hotspot/share/compiler/oopMap.hpp line 115:

> 113:     stream->write_int(value());
> 114:     if(is_callee_saved() || is_derived_oop()) {
> 115:       stream->write_int(checked_cast<int>(content_reg()->value()));

int --> juint, we need checked_cast<juint> here because of -Wsign-conversion

src/hotspot/share/compiler/oopMap.hpp line 115:

> 113:     stream->write_int(value());
> 114:     if(is_callee_saved() || is_derived_oop()) {
> 115:       stream->write_int(content_reg()->value());

Suggestion:

      stream->write_int(checked_cast<juint>(content_reg()->value()));

src/hotspot/share/gc/g1/g1CodeRootSet.cpp line 192:

> 190:     // we would grow again quickly.
> 191:     const float WantedLoadFactor = 0.5;
> 192:     assert((current_size / WantedLoadFactor) <= SIZE_MAX, "table overflow");

Surprisingly, this might not work.  See https://bugs.openjdk.org/browse/JDK-8287052.

src/hotspot/share/gc/parallel/mutableNUMASpace.cpp line 712:

> 710:   os::page_info page_expected, page_found;
> 711:   page_expected.size = page_size;
> 712:   page_expected.lgrp_id = lgrp_id();

Suggestion:

  page_expected.lgrp_id = checked_cast<int>(lgrp_id());

uint --> int
Or maybe fix the types to be the same.

src/hotspot/share/utilities/align.hpp line 75:

> 73: template<typename T, typename A, ENABLE_IF(std::is_integral<T>::value)>
> 74: constexpr T align_up(T size, A alignment) {
> 75:   T adjusted = checked_cast<T, true>(size + alignment_mask(alignment));

I guess the checked_cast is needed for sizeof(T) < sizeof(int), but there is still a possible signed overflow UB here.

src/hotspot/share/utilities/checkedCast.hpp line 55:

> 53:   static constexpr bool check_range(From from) {
> 54:     To to_max = std::numeric_limits<To>::max();
> 55:     return from <= static_cast<From>(to_max);

Don't we need to check that From is big enough to contain to_max?
Are we allowed to use checked_cast for signed to unsigned widening?
    checked_cast<uint64_t, int32_t> // fail if source is negative

src/hotspot/share/utilities/checkedCast.hpp line 100:

> 98:   static_assert(permit_tautology || is_narrowing, "tautological checked_cast");
> 99:   constexpr bool operator()(From from) const {
> 100:     return !is_narrowing || (static_cast<From>(static_cast<To>(from)) == from);

OK, so we are allowing compiler-specific behavior now?  Does that mean we can get rid of the weird-looking `reinterpret_cast<TYPE&>(ures)` in `JAVA_INTEGER_OP`?

src/hotspot/share/utilities/checkedCast.hpp line 139:

> 137:     return (from >= 0);
> 138:   }
> 139: };

So instead of checked_cast<uint64_t, int32_t> or checked_cast<uint,int>, callers should check from < 0 and then do a static_cast<>?  It might be better to allow checked_cast to support non-narrowed signed to unsigned, because I think the alternative is more error-prone.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359606831
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359617905
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359626718
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359617358
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359650061
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359652902
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359656238
PR Review Comment: https://git.openjdk.org/jdk/pull/16005#discussion_r1359658456


More information about the hotspot-dev mailing list