mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[debugger] do not leak results values in helper
GitOrigin-RevId: 66073216977cc93dad14823761bbf1551cf1b990
This commit is contained in:
committed by
intellij-monorepo-bot
parent
720f8b51e2
commit
58bd28151b
@@ -6,6 +6,7 @@ import com.intellij.debugger.engine.MethodInvokeUtils.getHelperExceptionStackTra
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.engine.evaluation.expression.BoxingEvaluator
|
||||
import com.intellij.debugger.impl.DebuggerUtilsAsync
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx.isVoid
|
||||
import com.intellij.debugger.impl.DebuggerUtilsImpl
|
||||
@@ -127,7 +128,14 @@ internal fun tryInvokeWithHelper(
|
||||
}
|
||||
|
||||
try {
|
||||
return InvocationResult(true, DebuggerUtilsImpl.invokeHelperMethod(evaluationContext, MethodInvoker::class.java, helperMethodName, invokerArgs, false))
|
||||
var value = DebuggerUtilsImpl.invokeHelperMethod(evaluationContext, MethodInvoker::class.java, helperMethodName, invokerArgs, false)
|
||||
if (value is ArrayReference) { // wrapped
|
||||
val wrapper = value
|
||||
value = value.getValue(0)
|
||||
DebuggerUtilsAsync.disableCollection(value)
|
||||
wrapper.setValue(0, null) // clear the reference TODO: make async
|
||||
}
|
||||
return InvocationResult(true, value)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
val helperExceptionStackTrace = getHelperExceptionStackTrace(evaluationContext, e)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.debugger.impl;
|
||||
|
||||
import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
|
||||
@@ -475,6 +475,16 @@ public final class DebuggerUtilsAsync {
|
||||
return toCompletableFuture(() -> virtualMachine.allClasses());
|
||||
}
|
||||
|
||||
public static CompletableFuture<Void> disableCollection(Value value) {
|
||||
if (value instanceof ObjectReference objectReference) {
|
||||
if (value instanceof ObjectReferenceImpl objectReferenceImpl && isAsyncEnabled()) {
|
||||
return objectReferenceImpl.disableCollectionAsync();
|
||||
}
|
||||
return toCompletableFuture(() -> objectReference.disableCollection());
|
||||
}
|
||||
return completedFuture(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule future completion in a separate command with the same priority and suspend context (if available)
|
||||
* as in the command being processed at the moment
|
||||
|
||||
@@ -5,11 +5,19 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"SSBasedInspection", "unused"})
|
||||
public final class MethodInvoker {
|
||||
// TODO: may leak objects here
|
||||
static ThreadLocal<Object> keptValue = new ThreadLocal<>();
|
||||
private static final ThreadLocal<List<Object>> keptValues = new ThreadLocal<List<Object>>() {
|
||||
@Override
|
||||
protected List<Object> initialValue() {
|
||||
return new LinkedList<>(); // LinkedList for fast elements removal
|
||||
}
|
||||
};
|
||||
|
||||
public static Object invoke0(MethodHandles.Lookup lookup, Class<?> cls, Object obj, String nameAndDescriptor, ClassLoader loader)
|
||||
throws Throwable {
|
||||
@@ -211,17 +219,40 @@ public final class MethodInvoker {
|
||||
}
|
||||
|
||||
Object result = method.invokeWithArguments(args);
|
||||
keptValue.set(result);
|
||||
return result;
|
||||
return keepReference(result, false);
|
||||
}
|
||||
catch (WrongMethodTypeException | ClassCastException e) {
|
||||
e.printStackTrace();
|
||||
keptValue.set(e);
|
||||
keepReference(e, true);
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
keptValue.set(e);
|
||||
keepReference(e, true);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object keepReference(Object ref, boolean soft) {
|
||||
List<Object> objects = keptValues.get();
|
||||
|
||||
// remove stale references first
|
||||
Iterator<Object> iterator = objects.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Object object = iterator.next();
|
||||
if (object instanceof Object[]) {
|
||||
if (((Object[])object)[0] == null) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
else if (object instanceof SoftReference) {
|
||||
if (((SoftReference<?>)object).get() == null) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object wrapper = soft ? new SoftReference<>(ref) : new Object[]{ref};
|
||||
objects.add(wrapper);
|
||||
return soft ? ref : wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user