mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-6771 BoxLayout throws mysterious NPEs due to previous exceptions
The checkRequests method only does layout initialization if it isn't initialized already. However, when an exception is thrown during the initialization, the layout may end up in a half-initialized state. Fix this by using the field that is initialized the last to check if the layout is initialized. If that field is null, it may mean that the layout isn't initialized or that the last attempt failed midway. Then we try again. This attempt can, of course, break for the same reason as the previous one, but in that case we'll at least get a stack trace pointing to a real cause of the error and not some mysterious NPE that seems to be impossible from the logic. The bug is that if we add a component that throws an exception in one of its methods called by BoxLayout, then the layout may end up in a half-initialized state that would mistakenly be considered fully initialized. Then it would try to access some fields and throw NPE with a stack trace that tells exactly nothing about what went wrong and where. This test checks for the presence of this bug by adding a broken component to a BoxLayout and then un-breaking this component and checking that an exception is thrown even though the component is no longer broken.
This commit is contained in:
committed by
Maxim Kartashev
parent
035ccf385d
commit
35da2d269e
@@ -459,7 +459,8 @@ public class BoxLayout implements LayoutManager2, Serializable {
|
||||
}
|
||||
|
||||
void checkRequests() {
|
||||
if (xChildren == null || yChildren == null) {
|
||||
// check yTotal, as it's assigned the last, to ensure initialization completed without exceptions:
|
||||
if (yTotal == null) {
|
||||
// The requests have been invalidated... recalculate
|
||||
// the request information.
|
||||
int n = target.getComponentCount();
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2024 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary BoxLayout doesn't ignore invisible components
|
||||
* @key headful
|
||||
* @run main NPECheckRequests
|
||||
*/
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
public class NPECheckRequests {
|
||||
JFrame frame;
|
||||
JPanel p;
|
||||
BrokenComponent foo;
|
||||
|
||||
public void init() {
|
||||
frame = new JFrame();
|
||||
p = new JPanel();
|
||||
BoxLayout boxLayout = new BoxLayout(p, BoxLayout.X_AXIS);
|
||||
p.setLayout(boxLayout);
|
||||
foo = new BrokenComponent();
|
||||
p.add(foo);
|
||||
frame.setLayout(new BorderLayout());
|
||||
frame.add(p, BorderLayout.CENTER);
|
||||
try {
|
||||
frame.pack();
|
||||
} catch (RuntimeException ignored) {
|
||||
// our broken component threw an exception
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
foo.broken = false;
|
||||
// check that the layout isn't in a broken state because of that exception
|
||||
frame.pack();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException,
|
||||
InvocationTargetException {
|
||||
NPECheckRequests test = new NPECheckRequests();
|
||||
SwingUtilities.invokeAndWait(test::init);
|
||||
SwingUtilities.invokeAndWait(test::start);
|
||||
}
|
||||
|
||||
private class BrokenComponent extends JPanel {
|
||||
|
||||
boolean broken = true;
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
if (broken) {
|
||||
throw new RuntimeException("Broken component");
|
||||
}
|
||||
return super.getPreferredSize();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user