From c595918fa72461276f8f33d19ebfff5530f4924d Mon Sep 17 00:00:00 2001 From: Martin Pokorny Date: Mon, 20 Apr 2026 22:45:13 +0200 Subject: [PATCH] Fix ConcurrentModificationException in getDeclaredResources and getResourcesFromProject Add synchronized(syncResources) blocks around iterations in getDeclaredResources() and getResourcesFromProject() to prevent ConcurrentModificationException when the resources list is modified concurrently by another thread. Also changes both methods to iterate over this.resources directly (inside the sync block) instead of this.getResources() which returns an unprotected reference. Fixes #933 --- .../LockableResourcesManager.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java index 2a84303f0..ee1a696f3 100644 --- a/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java +++ b/src/main/java/org/jenkins/plugins/lockableresources/LockableResourcesManager.java @@ -161,13 +161,15 @@ public List getReadOnlyResources() { /** Get declared resources, means only defined in config file (xml or JCaC yaml). */ @Restricted(NoExternalUse.class) public List getDeclaredResources() { - ArrayList declaredResources = new ArrayList<>(); - for (LockableResource r : this.getResources()) { - if (!r.isEphemeral() && !r.isNodeResource()) { - declaredResources.add(r); + synchronized (syncResources) { + ArrayList declaredResources = new ArrayList<>(); + for (LockableResource r : this.resources) { + if (!r.isEphemeral() && !r.isNodeResource()) { + declaredResources.add(r); + } } + return declaredResources; } - return declaredResources; } // --------------------------------------------------------------------------- @@ -231,14 +233,16 @@ public void setDeclaredResources(List declaredResources) { /** Get all resources used by project. */ @Restricted(NoExternalUse.class) public List getResourcesFromProject(String fullName) { - List matching = new ArrayList<>(); - for (LockableResource r : this.getResources()) { - String rName = r.getQueueItemProject(); - if (rName != null && rName.equals(fullName)) { - matching.add(r); + synchronized (syncResources) { + List matching = new ArrayList<>(); + for (LockableResource r : this.resources) { + String rName = r.getQueueItemProject(); + if (rName != null && rName.equals(fullName)) { + matching.add(r); + } } + return matching; } - return matching; } // ---------------------------------------------------------------------------