mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Prevent local value leaks via non-trivial field access
IDEA-230097 Inspection incorrectly shows "The call to 'assert true' always fails" on a Junit callback test GitOrigin-RevId: 5ae966d139391f72c7d015297b093523dba5e5e8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
90ca9a6360
commit
099d5fcf7c
+23
-3
@@ -466,14 +466,34 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
}
|
||||
if (!(value.getType() instanceof PsiArrayType) &&
|
||||
(TypeConstraint.fromDfType(dfType).isComparedByEquals() ||
|
||||
instruction.shouldFlushFields() || !(instruction.getResultType() instanceof PsiPrimitiveType))) {
|
||||
// For now drop locality on every qualified call except primitive returning pure calls
|
||||
// as value might escape through the return value
|
||||
instruction.shouldFlushFields() || mayLeakFromType(instruction.getResultType()))) {
|
||||
value = dropLocality(value, memState);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean mayLeakFromType(PsiType type) {
|
||||
// Complex value from field or method return call may contain back-reference to the object, so
|
||||
// local value could leak. Do not drop locality only for some simple values.
|
||||
if (type == null) return true;
|
||||
type = type.getDeepComponentType();
|
||||
return !(type instanceof PsiPrimitiveType) && !TypeUtils.isJavaLangString(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaInstructionState[] visitPush(ExpressionPushingInstruction<?> instruction,
|
||||
DataFlowRunner runner,
|
||||
DfaMemoryState memState,
|
||||
DfaValue value) {
|
||||
if (value instanceof DfaVariableValue && mayLeakFromType(value.getType())) {
|
||||
DfaVariableValue qualifier = ((DfaVariableValue)value).getQualifier();
|
||||
if (qualifier != null) {
|
||||
dropLocality(qualifier, memState);
|
||||
}
|
||||
}
|
||||
return super.visitPush(instruction, runner, memState, value);
|
||||
}
|
||||
|
||||
private Set<DfaCallState> addContractResults(MethodContract contract,
|
||||
Set<DfaCallState> states,
|
||||
DfaValueFactory factory,
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
// IDEA-230097
|
||||
class EscapeAnalysisLambdaInConstructor {
|
||||
public void incorrectInspection() {
|
||||
Callbackable callbackable = new Callbackable();
|
||||
EventListenerSetup listener = new EventListenerSetup();
|
||||
callbackable.setCallback(listener.listener);
|
||||
if (listener.listenerHasBeenCalled) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
callbackable.callCallback();
|
||||
|
||||
if (!listener.listenerHasBeenCalled) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Callbackable {
|
||||
Runnable callback;
|
||||
|
||||
public void setCallback(Runnable callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void callCallback(){
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
class EventListenerSetup {
|
||||
final Runnable listener;
|
||||
boolean listenerHasBeenCalled = false;
|
||||
|
||||
public EventListenerSetup() {
|
||||
this.listener = () -> listenerHasBeenCalled = true;
|
||||
}
|
||||
}
|
||||
@@ -222,6 +222,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
|
||||
|
||||
public void testMethodReferenceBoundToNullable() { doTestWithCustomAnnotations(); }
|
||||
public void testEscapeAnalysis() { doTest(); }
|
||||
public void testEscapeAnalysisLambdaInConstructor() { doTest(); }
|
||||
public void testThisAsVariable() { doTest(); }
|
||||
public void testQueuePeek() { doTest(); }
|
||||
public void testForeachCollectionElement() { doTest(); }
|
||||
|
||||
Reference in New Issue
Block a user