Skip to content

Commit

Permalink
Prevent CME in LaunchBarManager
Browse files Browse the repository at this point in the history
This change synchronizes access to LaunchBarManager.descriptors, to
avoid a ConcurrentModificationException when adding descriptors for 2
launches at the same time.

Fixes: #262
  • Loading branch information
trancexpress committed Jan 27, 2023
1 parent ccf8053 commit f8b4cb6
Showing 1 changed file with 40 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,13 @@ void init() throws CoreException {
ILaunchDescriptor last = null;
for (String id : split) {
Pair<String, String> key = toId(id);
ILaunchDescriptor desc = descriptors.get(key);
if (desc != null) {
descriptors.remove(key);
descriptors.put(key, desc);
last = desc;
synchronized (descriptors) {
ILaunchDescriptor desc = descriptors.get(key);
if (desc != null) {
descriptors.remove(key);
descriptors.put(key, desc);
last = desc;
}
}
}
// Set the active desc, with MRU, it should be the last one
Expand Down Expand Up @@ -304,7 +306,10 @@ private Pair<String, String> getTargetId(ILaunchTarget target) {
}

private void addDescriptor(Object launchObject, ILaunchDescriptor descriptor) throws CoreException {
descriptors.put(getDescriptorId(descriptor), descriptor);
Pair<String, String> descriptorId = getDescriptorId(descriptor);
synchronized (descriptors) {
descriptors.put(descriptorId, descriptor);
}
objectDescriptorMap.put(launchObject, descriptor);
setActiveLaunchDescriptor(descriptor);
}
Expand Down Expand Up @@ -371,7 +376,10 @@ public void launchObjectRemoved(Object launchObject) throws CoreException {
Activator.trace("launch object removed " + launchObject); //$NON-NLS-1$
ILaunchDescriptor descriptor = objectDescriptorMap.remove(launchObject);
if (descriptor != null) {
descriptors.remove(getDescriptorId(descriptor));
Pair<String, String> descriptorId = getDescriptorId(descriptor);
synchronized (descriptors) {
descriptors.remove(descriptorId);
}
if (descriptor.equals(activeLaunchDesc)) {
setActiveLaunchDescriptor(getLastUsedDescriptor());
}
Expand Down Expand Up @@ -413,15 +421,21 @@ public void launchObjectChanged(Object launchObject) throws CoreException {
private ILaunchDescriptor getLastUsedDescriptor() {
if (descriptors.size() == 0)
return null;
ILaunchDescriptor[] descs = descriptors.values().toArray(new ILaunchDescriptor[descriptors.size()]);
ILaunchDescriptor[] descs;
synchronized (descriptors) {
descs = descriptors.values().toArray(new ILaunchDescriptor[descriptors.size()]);
}
return descs[descs.length - 1];
}

@Override
public ILaunchDescriptor[] getLaunchDescriptors() {
// return descriptor in usage order (most used first). UI can sort them
// later as it wishes
ArrayList<ILaunchDescriptor> values = new ArrayList<>(descriptors.values());
ArrayList<ILaunchDescriptor> values = new ArrayList<>();
synchronized (descriptors) {
values.addAll(descriptors.values());
}
Collections.reverse(values);
return values.toArray(new ILaunchDescriptor[values.size()]);
}
Expand Down Expand Up @@ -475,8 +489,14 @@ public void setActiveLaunchDescriptor(ILaunchDescriptor descriptor) throws CoreE
Activator.trace("resync for " + descriptor); //$NON-NLS-1$
return;
}
if (descriptor != null && !descriptors.containsValue(descriptor)) {
throw new IllegalStateException(Messages.LaunchBarManager_1);
if (descriptor != null) {
boolean isContained;
synchronized (descriptors) {
isContained = descriptors.containsValue(descriptor);
}
if (!isContained) {
throw new IllegalStateException(Messages.LaunchBarManager_1);
}
}
if (descriptor == null) {
// do not set to null unless no descriptors
Expand All @@ -498,8 +518,10 @@ private void doSetActiveLaunchDescriptor(ILaunchDescriptor descriptor) {
if (descriptor != null) {
// keeps most used descriptor last
Pair<String, String> id = getDescriptorId(descriptor);
descriptors.remove(id);
descriptors.put(id, descriptor);
synchronized (descriptors) {
descriptors.remove(id);
descriptors.put(id, descriptor);
}
}
}

Expand All @@ -508,7 +530,11 @@ private void storeActiveDescriptor(ILaunchDescriptor descriptor) {
// Store the desc order, active one is the last one
StringBuffer buff = new StringBuffer();
// TODO: this can be very long string
for (Pair<String, String> key : descriptors.keySet()) {
ArrayList<Pair<String, String>> keys = new ArrayList<>();
synchronized (descriptors) {
keys.addAll(descriptors.keySet());
}
for (Pair<String, String> key : keys) {
if (buff.length() > 0) {
buff.append(',');
}
Expand Down

0 comments on commit f8b4cb6

Please sign in to comment.