mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
15 hours ago 5b773cad6b5768070a143d248f7933f0e3f7821e
Fix java/sleep-with-lock-held CodeQL alert in ControlPanelInfo.stopPooling() (#780)
1 files modified
59 ■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/ControlPanelInfo.java 59 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/datamodel/ControlPanelInfo.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2014-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.datamodel;
@@ -86,9 +87,17 @@
  private final IconPool iconPool = new IconPool();
  private long poolingPeriod = 20000;
  /**
   * Guards the pooling thread life cycle.  A dedicated lock is used on purpose:
   * the pooling thread calls methods that are synchronized on this object (for
   * instance {@link #regenerateDescriptor()}), so waiting for that thread to
   * die while holding the monitor of this object would deadlock.
   */
  private final Object poolingLock = new Object();
  /** Guarded by {@link #poolingLock}. */
  private Thread poolingThread;
  private boolean stopPooling;
  private boolean pooling;
  /** Read by the pooling thread without any lock, hence volatile. */
  private volatile boolean stopPooling;
  private ApplicationTrustManager trustManager;
  private int connectTimeout = CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT;
@@ -694,13 +703,14 @@
   * specified as a parameter.  This method is asynchronous and it will start
   * the pooling in another thread.
   */
  public synchronized void startPooling()
  public void startPooling()
  {
    if (poolingThread != null)
    synchronized (poolingLock)
    {
      if (poolingThread != null && poolingThread.isAlive())
    {
      return;
    }
    pooling = true;
    stopPooling = false;
    poolingThread = new Thread(new Runnable()
@@ -717,36 +727,57 @@
            Thread.sleep(poolingPeriod);
          }
        }
          catch (InterruptedException e)
          {
            // stopPooling() asked this thread to stop.
          }
        catch (Throwable t)
        {
            logger.warn(LocalizableMessage.raw("Error polling the server: " + t, t));
        }
        pooling = false;
      }
    });
    poolingThread.start();
  }
  }
  /**
   * Stops pooling the server.  This method is synchronous, it does not return
   * until the pooling is actually stopped.
   */
  public synchronized void stopPooling()
  public void stopPooling()
  {
    synchronized (poolingLock)
  {
    stopPooling = true;
    while (poolingThread != null && pooling)
      boolean interrupted = false;
      if (poolingThread != null)
    {
      try
        // Keep interrupting the pooling thread until it dies: it may be blocked
        // in an operation that swallows the interruption.  Note that this must
        // not be done while holding the monitor of this object, see poolingLock.
        while (poolingThread.isAlive())
      {
        poolingThread.interrupt();
        Thread.sleep(100);
      }
      catch (Throwable t)
          try
      {
        // do nothing;
            poolingThread.join(100);
          }
          catch (InterruptedException e)
          {
            // Do not give up the wait: this method must not return before the
            // pooling thread has actually stopped.  The interruption is
            // propagated to the caller once the thread is dead.
            interrupted = true;
      }
    }
    poolingThread = null;
    pooling = false;
      }
      if (interrupted)
      {
        Thread.currentThread().interrupt();
      }
    }
  }
  /**