mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +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
@@ -466,14 +466,34 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
|||||||
}
|
}
|
||||||
if (!(value.getType() instanceof PsiArrayType) &&
|
if (!(value.getType() instanceof PsiArrayType) &&
|
||||||
(TypeConstraint.fromDfType(dfType).isComparedByEquals() ||
|
(TypeConstraint.fromDfType(dfType).isComparedByEquals() ||
|
||||||
instruction.shouldFlushFields() || !(instruction.getResultType() instanceof PsiPrimitiveType))) {
|
instruction.shouldFlushFields() || mayLeakFromType(instruction.getResultType()))) {
|
||||||
// For now drop locality on every qualified call except primitive returning pure calls
|
|
||||||
// as value might escape through the return value
|
|
||||||
value = dropLocality(value, memState);
|
value = dropLocality(value, memState);
|
||||||
}
|
}
|
||||||
return value;
|
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,
|
private Set<DfaCallState> addContractResults(MethodContract contract,
|
||||||
Set<DfaCallState> states,
|
Set<DfaCallState> states,
|
||||||
DfaValueFactory factory,
|
DfaValueFactory factory,
|
||||||
|
|||||||
@@ -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 testMethodReferenceBoundToNullable() { doTestWithCustomAnnotations(); }
|
||||||
public void testEscapeAnalysis() { doTest(); }
|
public void testEscapeAnalysis() { doTest(); }
|
||||||
|
public void testEscapeAnalysisLambdaInConstructor() { doTest(); }
|
||||||
public void testThisAsVariable() { doTest(); }
|
public void testThisAsVariable() { doTest(); }
|
||||||
public void testQueuePeek() { doTest(); }
|
public void testQueuePeek() { doTest(); }
|
||||||
public void testForeachCollectionElement() { doTest(); }
|
public void testForeachCollectionElement() { doTest(); }
|
||||||
|
|||||||
Reference in New Issue
Block a user