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

Valery Kharseko
22 hours ago 44b37afa94f2aa6dc575835ac508ed214f6b983a
Fix CodeQL warning-severity alerts: process stream ownership and two leaks (#799)
6 files modified
128 ■■■■■ changed files
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/Utils.java 21 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java 13 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java 13 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java 36 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java 36 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java 9 ●●●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/Utils.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2015-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.forgerock.opendj.maven.doc;
@@ -75,11 +76,15 @@
     * @throws IOException  Failed to make the copy.
     */
    static void copyFile(File original, File copy) throws IOException {
        copyInputStreamToFile(new FileInputStream(original), copy);
        try (InputStream input = new FileInputStream(original)) {
            copyInputStreamToFile(input, copy);
        }
    }
    /**
     * Copies the content of the original input stream to the copy.
     * <p>
     * The original input stream is closed on return, whether the copy succeeded or not.
     * @param original      The original input stream.
     * @param copy          The copy.
     * @throws IOException  Failed to make the copy.
@@ -88,12 +93,14 @@
        if (original == null) {
            throw new IOException("Could not read input to copy.");
        }
        createFile(copy);
        try (OutputStream outputStream = new FileOutputStream(copy)) {
            int bytesRead;
            byte[] buffer = new byte[4096];
            while ((bytesRead = original.read(buffer)) > 0) {
                outputStream.write(buffer, 0, bytesRead);
        try {
            createFile(copy);
            try (OutputStream outputStream = new FileOutputStream(copy)) {
                int bytesRead;
                byte[] buffer = new byte[4096];
                while ((bytesRead = original.read(buffer)) > 0) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } finally {
            closeSilently(original);
opendj-server-legacy/src/main/java/org/opends/quicksetup/installer/InstallerHelper.java
@@ -33,7 +33,6 @@
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
@@ -152,8 +151,7 @@
    try
    {
      process = processBuilder.start();
      final BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
      new OutputReader(err)
      new OutputReader(process.getErrorStream())
      {
        @Override
        public void processLine(final String line)
@@ -164,8 +162,7 @@
        }
      }.start();
      final BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream()));
      new OutputReader(out)
      new OutputReader(process.getInputStream())
      {
        @Override
        public void processLine(final String line)
@@ -182,8 +179,10 @@
    {
      if (process != null)
      {
        closeProcessStream(process.getErrorStream(), "error");
        closeProcessStream(process.getOutputStream(), "output");
        // The error and output streams of the process are owned by the readers started above,
        // which close them once drained. Only the stream writing to the standard input of the
        // process, which is never used here, is left to close.
        closeProcessStream(process.getOutputStream(), "input");
      }
    }
  }
opendj-server-legacy/src/main/java/org/opends/quicksetup/util/OutputReader.java
@@ -19,6 +19,8 @@
package org.opends.quicksetup.util;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -39,16 +41,17 @@
  /**
   * The protected constructor.
   * <p>
   * The reader is consumed until end of stream and then closed by this reader's thread, which is
   * only launched by {@link #start()}.
   * The stream is consumed until end of stream and then closed by this reader's thread, which is
   * only launched by {@link #start()}. Wrapping the stream is done by that thread as well, so that
   * this reader is the sole owner of every resource built on top of the stream.
   *
   * @param reader  the BufferedReader of the stop process.
   * @param stream  the output stream of the process to read.
   */
  public OutputReader(final BufferedReader reader) {
  public OutputReader(final InputStream stream) {
    thread = new Thread(new Runnable() {
      @Override
      public void run() {
        try (BufferedReader in = reader) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) {
          String line;
          while (null != (line = in.readLine())) {
            processLine(line);
opendj-server-legacy/src/main/java/org/opends/quicksetup/util/ServerController.java
@@ -19,6 +19,7 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
@@ -181,16 +182,9 @@
          logger.info(LocalizableMessage.raw("Launching stop command, argList: "+argList));
          Process process = pb.start();
          BufferedReader err =
            new BufferedReader(
                new InputStreamReader(process.getErrorStream()));
          BufferedReader out =
            new BufferedReader(
                new InputStreamReader(process.getInputStream()));
          /* Create these objects to resend the stop process output to the details area. */
          new StopReader(err, true);
          new StopReader(out, false);
          new StopReader(process.getErrorStream(), true);
          new StopReader(process.getInputStream(), false);
          int returnValue = process.waitFor();
@@ -388,11 +382,8 @@
    String startedId = getStartedId();
    Process process = pb.start();
    BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream()));
    StartReader errReader = new StartReader(err, startedId, true);
    StartReader outputReader = new StartReader(out, startedId, false);
    StartReader errReader = new StartReader(process.getErrorStream(), startedId, true);
    StartReader outputReader = new StartReader(process.getInputStream(), startedId, false);
    int returnValue = process.waitFor();
@@ -546,12 +537,11 @@
    /**
     * The protected constructor.
     *
     * @param reader  the BufferedReader of the stop process.
     * @param isError a boolean indicating whether the BufferedReader
     * @param stream  the stream of the stop process to read.
     * @param isError a boolean indicating whether the stream
     *        corresponds to the standard error or to the standard output.
     */
    public StopReader(final BufferedReader reader,
                                      final boolean isError) {
    public StopReader(final InputStream stream, final boolean isError) {
      final LocalizableMessage errorTag =
              isError ?
                      INFO_ERROR_READING_ERROROUTPUT.get() :
@@ -562,7 +552,7 @@
        @Override
        public void run() {
          // The reader is owned by this thread, which closes it once the stream is drained.
          try (BufferedReader in = reader) {
          try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) {
            String line = in.readLine();
            while (line != null) {
              if (application != null) {
@@ -626,13 +616,13 @@
    /**
     * The protected constructor.
     * @param reader the BufferedReader of the start process.
     * @param stream the stream of the start process to read.
     * @param startedId the message ID that this class can use to know whether
     * the start is over or not.
     * @param isError a boolean indicating whether the BufferedReader
     * @param isError a boolean indicating whether the stream
     * corresponds to the standard error or to the standard output.
     */
    public StartReader(final BufferedReader reader, final String startedId,
    public StartReader(final InputStream stream, final String startedId,
        final boolean isError)
    {
      final LocalizableMessage errorTag =
@@ -648,7 +638,7 @@
        public void run()
        {
          // The reader is owned by this thread, which closes it once the stream is drained.
          try (BufferedReader in = reader)
          try (BufferedReader in = new BufferedReader(new InputStreamReader(stream)))
          {
            String line = in.readLine();
            while (line != null)
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ID2Entry.java
@@ -260,16 +260,7 @@
        {
          return Entry.decode(reader, compressedSchema);
        }
        InputStream is = reader.asInputStream();
        if ((format & ENCRYPT_ENTRY) == ENCRYPT_ENTRY)
        {
          is = getCryptoManager().getCipherInputStream(is);
        }
        if ((format & COMPRESS_ENTRY) == COMPRESS_ENTRY)
        {
          is = new InflaterInputStream(is);
        }
        try (InputStream entryStream = is)
        try (InputStream entryStream = newEntryInputStream(reader, format))
        {
          byte[] data = new byte[encodedEntryLen];
          int readBytes;
@@ -295,6 +286,31 @@
      }
    }
    /**
     * Returns the stream to read the encoded entry from, decorated as mandated by the format.
     * <p>
     * The returned stream owns the streams it wraps, so closing it closes the whole chain.
     *
     * @param reader the reader positioned at the start of the encoded entry.
     * @param format the format byte of the encoded entry.
     * @return the stream to read the encoded entry from.
     * @throws CryptoManagerException If the cipher input stream cannot be created.
     */
    private static InputStream newEntryInputStream(ByteSequenceReader reader, int format)
        throws CryptoManagerException
    {
      InputStream is = reader.asInputStream();
      if ((format & ENCRYPT_ENTRY) == ENCRYPT_ENTRY)
      {
        is = getCryptoManager().getCipherInputStream(is);
      }
      if ((format & COMPRESS_ENTRY) == COMPRESS_ENTRY)
      {
        is = new InflaterInputStream(is);
      }
      return is;
    }
    private ByteString encode(Entry entry, DataConfig dataConfig) throws DirectoryException
    {
      encodeVolatile(entry, dataConfig);
opendj-server-legacy/src/main/java/org/opends/server/tasks/ImportTask.java
@@ -328,6 +328,15 @@
      }
    }
    if (backend == null)
    {
      // Unreachable as long as the checks above hold: a null backend ID implies at least one
      // include branch, and every include branch either resolves to a backend or is rejected.
      // The guard mirrors the one in runTask() and keeps the dereference below safe.
      LocalizableMessage message = ERR_LDIFIMPORT_NO_BACKENDS_FOR_ID.get();
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
    }
    // Make sure the selected backend will handle all the include branches
    defaultIncludeBranches = new ArrayList<>(backend.getBaseDNs());