8386700: Class-File API: StackMapGenerator.setLocalsFromArg leaves stale locals, generating invalid stack maps

Reviewed-by: liach
This commit is contained in:
Adam Sotona 2026-06-17 07:54:25 +00:00
parent 5fbce068bd
commit ef5b328ce5
2 changed files with 31 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -1110,6 +1110,9 @@ public final class StackMapGenerator {
locals[localsSize++] = type;
}
}
if (locals != null && localsSize < locals.length) {
Arrays.fill(locals, localsSize, locals.length, Type.TOP_TYPE);
}
this.localsSize = localsSize;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,7 +24,7 @@
/*
* @test
* @summary Testing Classfile stack maps generator.
* @bug 8305990 8320222 8320618 8335475 8338623 8338661 8343436
* @bug 8305990 8320222 8320618 8335475 8338623 8338661 8343436 8386700
* @build testdata.*
* @run junit StackMapsTest
*/
@ -415,4 +415,29 @@ class StackMapsTest {
assertEquals(2, code.maxLocals());
assertEquals(2, code.maxStack());
}
@Test
void testStaleLocals() {
byte[] bytes = ClassFile.of().build(ClassDesc.of("Repro"), clb -> clb
.withMethodBody("m", MethodTypeDesc.of(CD_void, CD_int), ACC_STATIC, cob -> {
var cond = cob.newLabel();
var back = cob.newLabel();
var fwd = cob.newLabel();
cob.iconst_0()
.istore(1) // stale slot 1 holding of a long incorrectly clears slot 0 in the second round
.iload(1)
.ifeq(cond) // conditional branch triggers merge of frames
.goto_(fwd)
.labelBinding(cond)
.iload(0) // invalid stack frame when slot 0 is cleared
.pop()
.labelBinding(back)
.return_()
.labelBinding(fwd)
.lconst_0()
.lstore(0) // long overrides slots 0 and 1
.goto_(back); // back jump with modified locals triggers second round with stale slots
}));
assertEmpty(ClassFile.of().verify(bytes));
}
}