From 7af51501d5a70e6cdff45d7c1c804f0e820d1d3a Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Tue, 04 Aug 2026 11:53:39 +0000
Subject: [PATCH] Fix CodeQL note-severity alerts: Thread.run() calls and getters leaking internal state (#847)
---
opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java | 4 +
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/StatsThread.java | 11 ++-
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SuffixesToReplicateOptions.java | 22 ++++---
opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPConnectionOptions.java | 4 +
opendj-cli/src/main/java/com/forgerock/opendj/cli/FileBasedArgument.java | 4 +
opendj-server-legacy/src/main/java/org/opends/server/admin/client/cli/SecureConnectionCliArgs.java | 7 +
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java | 2
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/Category.java | 20 +++++-
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/MainActionsPane.java | 3
opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java | 34 ++++++++---
opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java | 12 +++
11 files changed, 91 insertions(+), 32 deletions(-)
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java
index db3da96..3cbf468 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package com.forgerock.opendj.cli;
@@ -374,6 +375,9 @@
/**
* Retrieves the set of string values for this argument.
+ * <p>
+ * The returned list is the live one: {@code ListBackends} removes the backend identifiers it
+ * could not resolve from it, and {@code InstallDS} adds the default base DN to it.
*
* @return The set of string values for this argument.
*/
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
index b80f5d4..548cb3c 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
@@ -582,10 +582,20 @@
* Retrieves the set of unnamed trailing arguments that were provided on the
* command line.
*
- * @return The set of unnamed trailing arguments that were provided on the
+ * @return A copy of the set of unnamed trailing arguments that were provided on the
* command line.
*/
public ArrayList<String> getTrailingArguments() {
+ return new ArrayList<>(trailingArguments);
+ }
+
+ /**
+ * Returns the live list of unnamed trailing arguments, so that a sub-class parsing the
+ * command line can fill it in. Unlike {@link #getTrailingArguments()}, this does not copy.
+ *
+ * @return The list of unnamed trailing arguments held by this parser.
+ */
+ List<String> trailingArguments() {
return trailingArguments;
}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/FileBasedArgument.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/FileBasedArgument.java
index 7a8d962..924f811 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/FileBasedArgument.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/FileBasedArgument.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package com.forgerock.opendj.cli;
@@ -105,6 +106,9 @@
/**
* Retrieves a map between the filenames specified on the command line and
* the first lines read from those files.
+ * <p>
+ * The returned map is the live one: the tools building an equivalent command line add
+ * entries to it, so that a password read interactively is displayed as a password file.
*
* @return A map between the filenames specified on the command line and the
* first lines read from those files.
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
index 495b03b..dbd5f2c 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
@@ -318,7 +318,7 @@
@Override
public void parseArguments(String[] rawArguments, Properties argumentProperties) throws ArgumentException {
this.subCommand = null;
- final ArrayList<String> trailingArguments = getTrailingArguments();
+ final List<String> trailingArguments = trailingArguments();
trailingArguments.clear();
setUsageOrVersionDisplayed(false);
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/StatsThread.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/StatsThread.java
index 6e55710..565efc2 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/StatsThread.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/StatsThread.java
@@ -12,6 +12,7 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package com.forgerock.opendj.ldap.tools;
@@ -47,8 +48,12 @@
* Statistics thread base implementation.
* <p>
* The goal of this class is to compute and print rate tool general statistics.
+ * <p>
+ * This class is a {@link Runnable} rather than a {@link Thread}: it is run periodically by
+ * {@code statThreadScheduler}, and {@link #stopRecording(boolean)} calls {@link #run()} directly
+ * to print the last line of statistics.
*/
-class StatsThread extends Thread {
+class StatsThread implements Runnable {
static final String STAT_ID_PREFIX = "org.forgerock.opendj.";
@@ -263,10 +268,10 @@
private final RateReporter reporter;
private long startTimeMs;
private volatile boolean warmingUp;
- private final ScheduledExecutorService statThreadScheduler = Executors.newSingleThreadScheduledExecutor();
+ private final ScheduledExecutorService statThreadScheduler =
+ Executors.newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, "Stats Thread"));
StatsThread(final PerformanceRunner performanceRunner, final ConsoleApplication application) {
- super("Stats Thread");
resetStats();
this.performanceRunner = performanceRunner;
this.app = application;
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/Category.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/Category.java
index 86797b5..d2766c8 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/Category.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/Category.java
@@ -13,11 +13,14 @@
*
* Copyright 2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.guitools.controlpanel.datamodel;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import org.forgerock.i18n.LocalizableMessage;
@@ -30,7 +33,7 @@
public class Category
{
private LocalizableMessage name;
- private ArrayList<Action> actions = new ArrayList<>();
+ private final List<Action> actions = new ArrayList<>();
/**
* Returns the name of the category.
@@ -52,10 +55,19 @@
/**
* Returns the actions associated with this category.
- * @return the actions associated with this category.
+ * @return an unmodifiable view of the actions associated with this category.
*/
- public ArrayList<Action> getActions()
+ public List<Action> getActions()
{
- return actions;
+ return Collections.unmodifiableList(actions);
+ }
+
+ /**
+ * Adds an action to this category.
+ * @param action the action to add.
+ */
+ public void addAction(Action action)
+ {
+ actions.add(action);
}
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/MainActionsPane.java b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/MainActionsPane.java
index 69fc755..6ac2232 100644
--- a/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/MainActionsPane.java
+++ b/opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/MainActionsPane.java
@@ -13,6 +13,7 @@
*
* Copyright 2008-2009 Sun Microsystems, Inc.
* Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.guitools.controlpanel.ui;
@@ -272,7 +273,7 @@
action.setAssociatedPanel(classes.get(classIndex));
classIndex ++;
- category.getActions().add(action);
+ category.addAction(action);
}
categories.add(category);
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SuffixesToReplicateOptions.java b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SuffixesToReplicateOptions.java
index 7a5b2f9..ac76db6 100644
--- a/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SuffixesToReplicateOptions.java
+++ b/opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/SuffixesToReplicateOptions.java
@@ -13,9 +13,11 @@
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.quicksetup.installer;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -46,10 +48,10 @@
REPLICATE_WITH_EXISTING_SUFFIXES
}
- private Type type;
- private Set<SuffixDescriptor> availableSuffixes;
- private Set<SuffixDescriptor> suffixesToReplicate;
- private Map<String, BackendTypeUIAdapter> backendsToReplicate;
+ private final Type type;
+ private final Set<SuffixDescriptor> availableSuffixes;
+ private final Set<SuffixDescriptor> suffixesToReplicate;
+ private final Map<String, BackendTypeUIAdapter> backendsToReplicate;
/**
* Constructor for the SuffixesToReplicateOptions object.
@@ -84,9 +86,9 @@
Set<SuffixDescriptor> suffixesToReplicate, Map<String, BackendTypeUIAdapter> backendsToReplicate)
{
this.type = type;
- this.availableSuffixes = new LinkedHashSet<>(availableSuffixes);
- this.suffixesToReplicate = new LinkedHashSet<>(suffixesToReplicate);
- this.backendsToReplicate = new HashMap<>(backendsToReplicate);
+ this.availableSuffixes = Collections.unmodifiableSet(new LinkedHashSet<>(availableSuffixes));
+ this.suffixesToReplicate = Collections.unmodifiableSet(new LinkedHashSet<>(suffixesToReplicate));
+ this.backendsToReplicate = Collections.unmodifiableMap(new HashMap<>(backendsToReplicate));
}
/**
@@ -103,7 +105,7 @@
/**
* Returns the set of suffixes available for replication.
*
- * @return the set of suffixes available for replication.
+ * @return an unmodifiable set of the suffixes available for replication.
*/
public Set<SuffixDescriptor> getAvailableSuffixes()
{
@@ -113,7 +115,7 @@
/**
* The set of suffixes that we must replicate with.
*
- * @return the set of suffixes that we must replicate with.
+ * @return an unmodifiable set of the suffixes that we must replicate with.
*/
public Set<SuffixDescriptor> getSuffixes()
{
@@ -123,7 +125,7 @@
/**
* Returns a map which associate backend names and backend types.
*
- * @return A map which associate backend names and backend types.
+ * @return an unmodifiable map which associate backend names and backend types.
*/
public Map<String, BackendTypeUIAdapter> getSuffixBackendTypes()
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/admin/client/cli/SecureConnectionCliArgs.java b/opendj-server-legacy/src/main/java/org/opends/server/admin/client/cli/SecureConnectionCliArgs.java
index 4e34adb..abc2952 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/admin/client/cli/SecureConnectionCliArgs.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/admin/client/cli/SecureConnectionCliArgs.java
@@ -13,6 +13,7 @@
*
* Copyright 2007-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.admin.client.cli;
@@ -159,7 +160,9 @@
* @throws ArgumentException
* If there is a problem with any of the parameters used to create
* this argument.
- * @return a ArrayList with the options created.
+ * @return a new set holding the options created. Callers may add their own arguments to it:
+ * the set is a copy, so doing so does not add them to the connection arguments this
+ * object reports through {@link #argumentsPresent()}.
*/
public Set<Argument> createGlobalArguments() throws ArgumentException
{
@@ -230,7 +233,7 @@
connectTimeoutArg = connectTimeOutArgument();
argList.add(connectTimeoutArg);
- return argList;
+ return new LinkedHashSet<>(argList);
}
/**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
index 5949582..68e2999 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
@@ -14,6 +14,7 @@
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
* Portions Copyright 2025-2026 3A Systems LLC.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.replication.service;
@@ -885,11 +886,11 @@
if (initReqMsg != null)
{
// Do this work in a thread to allow replay thread continue working
- ExportThread exportThread = new ExportThread(
+ ExportTask exportTask = new ExportTask(
initReqMsg.getSenderID(), initReqMsg.getInitWindow());
exportThreadPool.execute(() -> {
- Thread.currentThread().setName(exportThread.getName());
- exportThread.run();
+ Thread.currentThread().setName(exportTask.getName());
+ exportTask.run();
});
}
}
@@ -1039,20 +1040,23 @@
*/
/**
- * This thread is launched when we want to export data to another server.
+ * This task is submitted to the export thread pool when we want to export data to another
+ * server.
*
* When a task is created locally (so this local server is the initiator)
* of the export (Example: dsreplication initialize-all),
- * this thread is NOT used but the task thread is running the export instead).
+ * this task is NOT used but the task thread is running the export instead).
*/
- private class ExportThread extends DirectoryThread
+ private class ExportTask implements Runnable
{
/** Id of server that will be initialized. */
private final int serverIdToInitialize;
private final int initWindow;
+ /** Name given to the pool thread which runs this task. */
+ private final String name;
/**
- * Constructor for the ExportThread.
+ * Constructor for the ExportTask.
*
* @param serverIdToInitialize
* serverId of server that will receive entries
@@ -1060,14 +1064,24 @@
* The value of the initialization window for flow control between
* the importer and the exporter.
*/
- public ExportThread(int serverIdToInitialize, int initWindow)
+ public ExportTask(int serverIdToInitialize, int initWindow)
{
- super("Export thread from serverId=" + getServerId() + " to serverId="
- + serverIdToInitialize);
+ this.name = "Export thread from serverId=" + getServerId() + " to serverId="
+ + serverIdToInitialize;
this.serverIdToInitialize = serverIdToInitialize;
this.initWindow = initWindow;
}
+ /**
+ * Returns the name of this task, used to name the thread running it.
+ *
+ * @return the name of this task
+ */
+ public String getName()
+ {
+ return name;
+ }
+
@Override
public void run()
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPConnectionOptions.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPConnectionOptions.java
index 1bdbf7d..bb70bc7 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPConnectionOptions.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPConnectionOptions.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions Copyright 2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.tools;
@@ -174,6 +175,9 @@
/**
* Get the SASL options used for authentication.
+ * <p>
+ * The returned map is the live set of properties: callers may add or remove properties
+ * through it, as the DSML gateway does when it drops the authorization identity.
*
* @return The SASL options used for authentication.
*/
--
Gitblit v1.10.0