ConcurrentModificationException

Describe the bug

JavaLogFactory.java's readLoggerConfiguration function throws ConcurrentModificationException at this line

if (System.getProperties().keySet().stream().anyMatch(propKey ->
        "java.util.logging.config.class".equals(propKey) || "java.util.logging.config.file".equals(propKey)))

in a multi-threaded environment when another thread is concurrently setting system properties while ESAPI is iterating over system properties.

Specify what ESAPI version(s) you are experiencing this bug in

2.5.2.0

To Reproduce

public class Reproduce {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    long time = System.currentTimeMillis();
                    // Emulate another thread modifying system properties
                    System.setProperty(time + "", time + "");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }); t.start();
        EsapiThread esapiThread = new EsapiThread();
        esapiThread.start();
    }

    private static class EsapiThread extends Thread {
        public void run() {
            // Emulate the code of JavaLogFactory in ESAPI
            System.getProperties().keySet().stream().anyMatch(a -> {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                return "dummy".equals(a);
            });
        }
    }
}

Expected behavior

Proposed change: copy the System.getProperties().keySet() to a new collection and iterating over the new collection instead of the original one to avoid thread safety problem.

Platform environment (please complete the following information)

  • JDK version: JDK8