Skip to content

Commit 1b2931a

Browse files
committed
CommandLineOptions: disallow recursive embedding of @-files.
And tests.
1 parent 25ce685 commit 1b2931a

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

core/src/main/java/com/google/googlejavaformat/java/CommandLineOptionsParser.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static java.nio.charset.StandardCharsets.UTF_8;
1818

1919
import com.google.common.base.CharMatcher;
20+
import com.google.common.base.Preconditions;
2021
import com.google.common.base.Splitter;
2122
import com.google.common.collect.ImmutableRangeSet;
2223
import com.google.common.collect.Range;
@@ -25,7 +26,9 @@
2526
import java.nio.file.Files;
2627
import java.nio.file.Path;
2728
import java.nio.file.Paths;
29+
import java.util.ArrayDeque;
2830
import java.util.ArrayList;
31+
import java.util.Deque;
2932
import java.util.Iterator;
3033
import java.util.List;
3134

@@ -41,7 +44,7 @@ final class CommandLineOptionsParser {
4144
static CommandLineOptions parse(Iterable<String> options) {
4245
CommandLineOptions.Builder optionsBuilder = CommandLineOptions.builder();
4346
List<String> expandedOptions = new ArrayList<>();
44-
expandParamsFiles(options, expandedOptions);
47+
expandParamsFiles(options, expandedOptions, new ArrayDeque<>());
4548
Iterator<String> it = expandedOptions.iterator();
4649
while (it.hasNext()) {
4750
String option = it.next();
@@ -186,7 +189,7 @@ private static Range<Integer> parseRange(String arg) {
186189
* Pre-processes an argument list, expanding arguments of the form {@code @filename} by reading
187190
* the content of the file and appending whitespace-delimited options to {@code arguments}.
188191
*/
189-
private static void expandParamsFiles(Iterable<String> args, List<String> expanded) {
192+
private static void expandParamsFiles(Iterable<String> args, List<String> expanded, Deque<String> paramFilesStack) {
190193
for (String arg : args) {
191194
if (arg.isEmpty()) {
192195
continue;
@@ -196,13 +199,20 @@ private static void expandParamsFiles(Iterable<String> args, List<String> expand
196199
} else if (arg.startsWith("@@")) {
197200
expanded.add(arg.substring(1));
198201
} else {
199-
Path path = Paths.get(arg.substring(1));
202+
String filename = arg.substring(1);
203+
if (paramFilesStack.contains(filename)) {
204+
throw new IllegalArgumentException("parameter file was included recursively: " + filename);
205+
}
206+
paramFilesStack.push(filename);
207+
Path path = Paths.get(filename);
200208
try {
201209
String sequence = new String(Files.readAllBytes(path), UTF_8);
202-
expandParamsFiles(ARG_SPLITTER.split(sequence), expanded);
210+
expandParamsFiles(ARG_SPLITTER.split(sequence), expanded, paramFilesStack);
203211
} catch (IOException e) {
204212
throw new UncheckedIOException(path + ": could not read file: " + e.getMessage(), e);
205213
}
214+
String finishedFilename = paramFilesStack.pop();
215+
Preconditions.checkState(filename.equals(finishedFilename));
206216
}
207217
}
208218
}

core/src/test/java/com/google/googlejavaformat/java/CommandLineOptionsParserTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.google.common.truth.Truth8.assertThat;
1919
import static java.nio.charset.StandardCharsets.UTF_8;
2020
import static org.junit.Assert.fail;
21+
import static org.junit.Assert.assertThrows;
2122

2223
import com.google.common.collect.ImmutableList;
2324
import com.google.common.collect.Range;
@@ -179,6 +180,44 @@ public void paramsFile() throws IOException {
179180
assertThat(options.files()).containsExactly("L", "M", "ℕ", "@O", "P", "Q");
180181
}
181182

183+
@Test
184+
public void paramsFileWithNesting() throws IOException {
185+
Path outer = testFolder.newFile("outer").toPath();
186+
Path exit = testFolder.newFile("exit").toPath();
187+
Path nested1 = testFolder.newFile("nested1").toPath();
188+
Path nested2 = testFolder.newFile("nested2").toPath();
189+
Path nested3 = testFolder.newFile("nested3").toPath();
190+
191+
String[] args = {"--dry-run", "@" + exit, "L", "@" + outer, "U"};
192+
193+
Files.write(exit, "--set-exit-if-changed".getBytes(UTF_8));
194+
Files.write(outer, ("M\n@" + nested1.toAbsolutePath() + "\nT").getBytes(UTF_8));
195+
Files.write(nested1, ("ℕ\n@" + nested2.toAbsolutePath() + "\nS").getBytes(UTF_8));
196+
Files.write(nested2, ("O\n@" + nested3.toAbsolutePath() + "\nR").getBytes(UTF_8));
197+
Files.write(nested3, "P\n\n \n@@Q\n".getBytes(UTF_8));
198+
199+
CommandLineOptions options = CommandLineOptionsParser.parse(Arrays.asList(args));
200+
assertThat(options.files()).containsExactly("L", "M", "ℕ", "O", "P", "@Q", "R", "S", "T", "U");
201+
}
202+
203+
@Test
204+
public void paramsFileWithRecursion() throws IOException {
205+
Path outer = testFolder.newFile("outer").toPath();
206+
Path exit = testFolder.newFile("exit").toPath();
207+
Path nested1 = testFolder.newFile("nested1").toPath();
208+
Path nested2 = testFolder.newFile("nested2").toPath();
209+
210+
String[] args = {"--dry-run", "@" + exit, "L", "@" + outer, "U"};
211+
212+
Files.write(exit, "--set-exit-if-changed".getBytes(UTF_8));
213+
Files.write(outer, ("M\n@" + nested1.toAbsolutePath() + "\nT").getBytes(UTF_8));
214+
Files.write(nested1, ("ℕ\n@" + nested2.toAbsolutePath() + "\nS").getBytes(UTF_8));
215+
Files.write(nested2, ("O\n@" + nested1.toAbsolutePath() + "\nR").getBytes(UTF_8));
216+
217+
Exception exception = assertThrows(IllegalArgumentException.class, () -> CommandLineOptionsParser.parse(Arrays.asList(args)));
218+
assertThat(exception.getMessage().startsWith("parameter file was included recursively: ")).isTrue();
219+
}
220+
182221
@Test
183222
public void assumeFilename() {
184223
assertThat(

0 commit comments

Comments
 (0)