From fff741490367861eb6e939e9da266503b4ba933c Mon Sep 17 00:00:00 2001 From: fschumacher Date: Mon, 20 Apr 2026 13:49:31 +0200 Subject: [PATCH] Fix: Make concurrent CSV Read function really thread safe Current implementation could hand out the same row to more than one thread at the same time and could loose track when wrapping around. To fix #6673 change to a AtomicInteger and a compareAndSet operation to allow thread safe wrap around. To guard against an endless loop in the case of an empty CSV file, we now throw an ISE in such a case. This fixes #6673 --- .../jmeter/functions/FileRowColContainer.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/functions/src/main/java/org/apache/jmeter/functions/FileRowColContainer.java b/src/functions/src/main/java/org/apache/jmeter/functions/FileRowColContainer.java index 9e2f9c608e5..03013c3b903 100644 --- a/src/functions/src/main/java/org/apache/jmeter/functions/FileRowColContainer.java +++ b/src/functions/src/main/java/org/apache/jmeter/functions/FileRowColContainer.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.jmeter.services.FileServer; import org.apache.jmeter.util.JMeterUtils; @@ -50,7 +51,7 @@ public class FileRowColContainer { ","); // $NON-NLS-1$ /** Keeping track of which row is next to be read. */ - private int nextRow; + private final AtomicInteger nextRow; /** Delimiter for this file */ private final String delimiter; @@ -59,7 +60,7 @@ public FileRowColContainer(String file, String delim) throws IOException, FileNo log.debug("FRCC({},{})", file, delim); fileName = file; delimiter = delim; - nextRow = 0; + nextRow = new AtomicInteger(0); fileData = new ArrayList<>(); load(); } @@ -68,7 +69,7 @@ public FileRowColContainer(String file) throws IOException, FileNotFoundExceptio log.debug("FRCC({})[{}]", file, DELIMITER); fileName = file; delimiter = DELIMITER; - nextRow = 0; + nextRow = new AtomicInteger(0); fileData = new ArrayList<>(); load(); } @@ -119,13 +120,18 @@ public String getColumn(int row, int col) throws IndexOutOfBoundsException { * */ public int nextRow() { - int row = nextRow; - nextRow++; - if (nextRow >= fileData.size()) {// 0-based - nextRow = 0; + int size = fileData.size(); + if (size == 0) { + throw new IllegalStateException("CSV file " + fileName + " has no data rows"); + } + while (true) { + int current = nextRow.get(); + int next = (current + 1) % size; + if (nextRow.compareAndSet(current, next)) { + log.debug("Row: {}", current); + return current; + } } - log.debug("Row: {}", row); - return row; } /**