RFR: 8332368: ubsan aarch64: immediate_aarch64.cpp:298:31: runtime error: shift exponent 32 is too large for 32-bit type 'int'
Andrew Dinn
adinn at openjdk.org
Thu Apr 17 14:13:51 UTC 2025
On Wed, 16 Apr 2025 18:32:16 GMT, Boris Ulasevich <bulasevich at openjdk.org> wrote:
> Running a linux-aarch64-server-fastdebug build with UBSAN (--enable-ubsan configure option) gives the following runtime error immediately on JVM start:
>
>
> ad_aarch64.hpp:7114:11: runtime error: shift exponent 100 is too large for 32-bit type 'unsigned int'
> # Pipeline_Use_Cycle_Mask::operator<<=(int) make/hotspot/ad_aarch64.hpp:7114
> # Pipeline_Use_Element::step(unsigned int) make/hotspot/ad_aarch64.hpp:7168
> # Pipeline_Use::step(unsigned int) make/hotspot/ad_aarch64.hpp:7216
> # Scheduling::step(unsigned int) src/hotspot/share/opto/output.cpp:2116
> # Scheduling::AddNodeToBundle(Node*, Block const*) src/hotspot/share/opto/output.cpp:2553
>
>
> The value of 100 comes from fixed_latency, defined in AD files:
>
> // Pipeline class for call.
> pipe_class pipe_class_call()
> %{
> single_instruction;
> fixed_latency(100);
> %}
>
>
> The fixed_latency value is used by the scheduler to model the occupancy of functional units over time. The occupancy is tracked using a uint mask value:
>
> fprintf(fp_hpp, "class Pipeline_Use_Element {\n");
> fprintf(fp_hpp, "protected:\n");
> fprintf(fp_hpp, " // Mask of used functional units\n");
> fprintf(fp_hpp, " uint _used;\n\n");
>
> When the scheduler virtually steps over the instruction, it shifts the masks left by the instruction's latency. The problem is that 100 is greater than sizeof(uint), and left-shifting by 100 effectively zeroes the _mask, but, according to the C++ standard, this is undefined behavior.
>
> We can find a number of fixed_latency(100) expressions in aarch64.ad, arm.ad, ppc.ad, riscv.ad, x86_64.ad files. Perhaps all of them deserve correction. I suggest leaving the AD files as they are, but limiting the shift value in case it exceeds the allowed maximum in a generated code:
>
> void step(uint cycles) {
> _used = 0;
> - _mask <<= cycles;
> + uint max_shift = 8 * sizeof(_mask) - 1;
> + _mask <<= (cycles < max_shift) ? cycles : max_shift;
> }
>
> In fact, this change does not affect the current behavior; we just eliminate the undefined behavior while preserving the intended semantics.
I believe this is the right solution.
-------------
Marked as reviewed by adinn (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/24696#pullrequestreview-2775910433
More information about the hotspot-compiler-dev
mailing list