From ec66ae4089c4220ce60f48de7b5b214a8b36bd9d Mon Sep 17 00:00:00 2001 From: Vogel612 Date: Tue, 18 Jan 2022 11:01:19 +0100 Subject: [PATCH] Widen restrictive archive traversal, fixes #1925 Includes unit-tests against a handrolled archive containing multiple other archives, each with a single classfile. --- CHANGELOG.md | 1 + .../classfile/impl/ClassPathBuilderTest.java | 36 ++++++++++++++++++ .../classfile/impl/ClassPathBuilder.java | 4 +- .../edu/umd/cs/findbugs/util/Archive.java | 2 + spotbugsTestCases/archives/nestedArchive.jar | Bin 0 -> 4129 bytes .../umd/cs/findbugs/test/AnalysisRunner.java | 11 +++++- .../umd/cs/findbugs/test/SpotBugsRule.java | 23 ++++++++++- 7 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 spotbugs-tests/src/test/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilderTest.java create mode 100644 spotbugsTestCases/archives/nestedArchive.jar diff --git a/CHANGELOG.md b/CHANGELOG.md index e0e4cd9298d..60f59413046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Currently the versioning policy of this project follows [Semantic Versioning v2. ## Unreleased - 2022-??-?? ### Fixed - Bumped Saxon-HE from 10.6 to 11.2 ([#1955](https://github.com/spotbugs/spotbugs/pull/1955)) +- Fixed traversal of nested archives governed by `-nested:true` ([#1930](https://github.com/spotbugs/spotbugs/pull/1930)) ## 4.6.0 - 2022-03-08 ### Fixed diff --git a/spotbugs-tests/src/test/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilderTest.java b/spotbugs-tests/src/test/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilderTest.java new file mode 100644 index 00000000000..f697a962cc3 --- /dev/null +++ b/spotbugs-tests/src/test/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilderTest.java @@ -0,0 +1,36 @@ +package edu.umd.cs.findbugs.classfile.impl; + +import edu.umd.cs.findbugs.AppVersion; +import edu.umd.cs.findbugs.BugCollection; +import edu.umd.cs.findbugs.test.SpotBugsRule; +import org.junit.Rule; +import org.junit.Test; + +import java.nio.file.Paths; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class ClassPathBuilderTest { + + @Rule + public SpotBugsRule analyzer = new SpotBugsRule(); + + @Test + public void nestedTraversalDisabled() { + BugCollection results = analyzer.performAnalysis((engine) -> { + engine.setScanNestedArchives(false); + engine.setNoClassOk(true); + }, Paths.get("../spotbugsTestCases/archives/nestedArchive.jar")); + AppVersion appInformation = results.getCurrentAppVersion(); + assertThat(appInformation.getNumClasses(), equalTo(0)); + } + + @Test + public void nestedTraversalEnabled() { + BugCollection results = analyzer.performAnalysis((engine) -> engine.setScanNestedArchives(true), + Paths.get("../spotbugsTestCases/archives/nestedArchive.jar")); + AppVersion appInformation = results.getCurrentAppVersion(); + assertThat(appInformation.getNumClasses(), equalTo(5)); + } +} diff --git a/spotbugs/src/main/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilder.java b/spotbugs/src/main/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilder.java index ffa7d6c068c..22f799ecb2b 100644 --- a/spotbugs/src/main/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilder.java +++ b/spotbugs/src/main/java/edu/umd/cs/findbugs/classfile/impl/ClassPathBuilder.java @@ -700,9 +700,9 @@ private void scanCodebase(IClassPath classPath, LinkedList workLis // If resource is a nested archive, add it to the worklist if (scanNestedArchives && (codeBase.isApplicationCodeBase() || codeBase instanceof DirectoryCodeBase) - && Archive.isLibraryFileName(entry.getResourceName())) { + && Archive.isArchiveFileName(entry.getResourceName())) { if (VERBOSE) { - System.out.println("Entry is an library!"); + System.out.println("Entry is a library!"); } ICodeBaseLocator nestedArchiveLocator = classFactory.createNestedArchiveCodeBaseLocator(codeBase, entry.getResourceName()); diff --git a/spotbugs/src/main/java/edu/umd/cs/findbugs/util/Archive.java b/spotbugs/src/main/java/edu/umd/cs/findbugs/util/Archive.java index d94444a3d56..56351a97bb2 100644 --- a/spotbugs/src/main/java/edu/umd/cs/findbugs/util/Archive.java +++ b/spotbugs/src/main/java/edu/umd/cs/findbugs/util/Archive.java @@ -71,6 +71,8 @@ private static String getExtension(String fileName) { return extension; } + @Deprecated + @SuppressWarnings("unused") // unused within the codebase, but deprecated until next release for public API reasons public static boolean isLibraryFileName(String fileName) { String extension = getExtension(fileName); return ".jar".equals(extension); diff --git a/spotbugsTestCases/archives/nestedArchive.jar b/spotbugsTestCases/archives/nestedArchive.jar new file mode 100644 index 0000000000000000000000000000000000000000..49e36070aec67347221f23c67e86f61656596200 GIT binary patch literal 4129 zcmZ{n2{crH8^^C*Ly|2-C_7;&FTQ)4Ox<<>?TXLNwzE_ z#+vL(meAPJJKo;jzw_36?)jbPJon!7`<#2u_j{l3PajG~&IAAeHNfU)VTk)6RA5R5 z0M5k4OuTD=biU(cr{V;6cUMO`*=ae8*}>hSZ=$plNPxo}UW1+?J*nq*c4unzgC(OS zC88+{DH(6HGrcwB4eC#GN`dgvi1c2d{OHC?&a(IRzO>;>k6Xyn{GzdooK>mpt;6xg z0TZt#*1YNte83&D?#ckb@n8$1oJ5}GRnI{O@K6J$*KxD;7A&D@-CDUE?XG!=I8$0d z2;;2%Ux={I8{JA^yw?5Z(kt@goKzqx5fBXl4Qy>RoA`{2y*|Hpc8#^-@kLjsfDdsM zP44eMr)rSCqU_A{7rV8jja5)pd0bxF?n;t|vMlR2h$W z@kVJlsP1vB&VqdShp&G7pT3J=f|r9tO!DfKmTeqWL(|`i#Qr#X1l|z(s^s1J{HQ!R zrXbNXQlRlYhtyNSz^k_>u3JmW*laT?I}Ztd+PYnFV~1zN&H=eQTDtqj*g{ZAg{9Zsb{EeW>KtNT-$;7q$OBe)fG{3df+dwf_h@x->i7{gpA^c77N<4+!T|;n=$8< zyI0)QI{0E8$b`|VP7RkdQQ)iKVnoBW2S}5;J=AlNg?gr-GRK7n;y#6Ih)TIwFLobT zYM}Euz38<9%Sxl_prxjE(PRQc+o)H=`tsT20E{R@HGy$6du}~_zNd21ZPigOX_?{0 zw&lRmsZ5mRcK2dVdPH9vKh`Zvpx1Z%yI11UsuO9$m^Dfe{)z2zZ#yUIi{tv z2HU@M$IEK#{jHS_?)8Z=#_bs=236)M?ap^+q)ZpCaKg`Gwdfei-uLG@tB4%FMj<<& z7xm=5A|PIzuh=V3+0|s;D0@;7%Y0g07lbipF}en3CQTKN-jxo~Mh-_BZKrqffmK=M zXm>}k{(*`c*~vfT8*v|GX*Wns@o(E8cP^EZthkz24N{voHtepJcG7dwzrH5bo4(1j z>$Fdy|6ePP`dS#~mc=1MEt zvxk4HS*vZB`qIpqHTw~B8kiwN7*SQutY)a)r3Z=yfxjj%pH&vyjO+)+F~sE5hw+Mu zsDG>S4xw)A*UTR?kVr1o)AdL8fyM~)DdW{iB$LMdQa1t@=>2>%8k~!zyf;vO!j#eK zR5nesirfBM?KyY{(N_e?39y`DF0SL@wE-o1e{_JSNGa%T_NGs~EDyR9w&l&tDSloW zxp`PAkUw-Ab`+_L?=D4~ctM_Z_pey$1V>%z(%0Q^W{74V!7<%)8uk$Q;rmpf6XH<1 zn7sVAa%l7DyXUlp8y3Zgok4i;n0gB*vwh983WOiQ13}86=_|l}IINFF^|KZ-77dpX z#M5IMrw+NVw0OH{!@_#r@~+kQ#hCI*se-d4kUD?cnnf(1V``*7YD}_D8HIKjY}rmQ z--g2u9v{*SZbp)UV(#)Ar_2XjOFIbB_Goq#&7r8VATi){f7WI3p>rfi%f#}v0y|oV zpm+@oHPfntHAi$PE;h=miL1LFw~Wf zk(yJd)(=>7d;Yo)f3J~*k>mL+3{}e%iKUAha;y{+GK`H$6X-Uo`e23I^`1@IXm0u|52Y1aS(X69GWhZ z0KjMB`m_4n;clM#C`|)6>rsq5j*kLcAuUyc)9KRIdirdIg#l-GxmM6!L|xRWx5^>1 zL%nPfSr1F%v6Mc`>28oYV>f%20_|-Z5z*}dX`D0M4qXbRLuc%d5*GZqvU^^H_VDbr z1A$5#8qDo_=Y?m%+(2#Pl7X3^ut69T7edfV)I_x@F=F0r6&)ZcMEM5si2dmozjo(& z#GEEuK@}^!YRKVb2j>s2{+YBD3atwY!a3?ft=M_{eVy~{lSoMfF45Ve~7!G`fY8EDmsH8eJ@n z`3Kf}wPd<~i+JwY(cW@H8AQnjD~dN-%3uEi>0D6y`_xQ*+l!!f%)DRcaKP-_5a9H@ z6l29JZYlμlqAPW|h-xc#^u9s@ebY5#RKwt3rwV`+ehX#fD|iPDI7Sgouh=7Zz) zXKCDnyZxi4m_V>0w}7Yx4e|9F3IJdvZlmnx2KO;U8+f=8^M#o0alG&}KpEilnI@s; z=_yS4)E5;t&6J|K6(VE1RZ40+sYh0Ja}!fc+pEJ93uO*PT`BE7wyAcXauE0{D1^Su zXD7N7*4AXT{{FFdMALH7QUDyN$pK>q(}FVblC`JHkoePOh7*#Xvs-2o?98VbA86Va za)e%t>&BE-Lw_ z2S$=coJ&6^la?lHlYocTb96E@o4D#&uL^QuXPZk3by|C2AlVY_Q3P70wNz=fV9W^u za+cUpNGmU%N%25SVfs1_W_j^Hf+DV)@)pADqow_~(~5%pNNp@z$sSQWSgx!>f})s2 zCq%t&UByjFIO-S=Q4~2}>3M|eI(W&tqhNM7TwzX; z*MR`Qu6UZ(YA%1xWAYWoeosYqm~dJ4wzm6MvO@@Y;rwnIHf?KbW_&w>0FmlJyCN!|%6`x3Qj8|JatC=ydB?jAAEo01W@%A>fO2@z+NQmbh{py$;Q)%6eLp=stj1&U|MMS(KDc zW#hrTTQEAGAl^3eNT=3~E5RaNjb|a@TGC^_)as-IzKO7x(~^WZ==Q!ns@1!u>GWawTXKa=ECu#<{Zz2?!`;E!EA4od6?9SYe8nhNqEZmD*)ryQO1<^=Yh|q1GG5B@*6giX#Nw&L>u!^znP>u(Au^gOnK+n@g@bvvy3IjF_MO zn4qBG7skx^Hn?>4)Jf6(eiHm&(f#pUcv5!VT?U)SGW%7_@_zOwF~6tWlbA@NAb-aY zGw(^vfX+nWF{b6Bc=K^ht{DG!e-iV1oH>a(MRdXM7-G0Ni9r{FNM8`Q|5fEpfA&8y z|8F#&#PCx82}2x|Co$8PRTq!H;#X~>{Mn!Un%{kS5<^G(Ck)Z0Co#@T?)YQOubSEN Vv;Xx=pa3WUGUBO&n(p|Q@Gl>*I9>n% literal 0 HcmV?d00001 diff --git a/test-harness-core/src/main/java/edu/umd/cs/findbugs/test/AnalysisRunner.java b/test-harness-core/src/main/java/edu/umd/cs/findbugs/test/AnalysisRunner.java index b29bc022dbb..8203868a719 100644 --- a/test-harness-core/src/main/java/edu/umd/cs/findbugs/test/AnalysisRunner.java +++ b/test-harness-core/src/main/java/edu/umd/cs/findbugs/test/AnalysisRunner.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; @@ -29,6 +30,7 @@ import edu.umd.cs.findbugs.BugRanker; import edu.umd.cs.findbugs.DetectorFactoryCollection; import edu.umd.cs.findbugs.FindBugs2; +import edu.umd.cs.findbugs.IFindBugsEngine; import edu.umd.cs.findbugs.Plugin; import edu.umd.cs.findbugs.PluginException; import edu.umd.cs.findbugs.Priorities; @@ -40,7 +42,7 @@ /** *

* This class runs analysis with SpotBugs. The target class files and - * auxClasspathEntries should be specified before you invoke {@link #run(Path...)} + * auxClasspathEntries should be specified before you invoke {@link #run(Consumer, Path...)} * method. *

* @@ -84,6 +86,12 @@ public AnalysisRunner addAuxClasspathEntry(Path path) { @Nonnull public BugCollectionBugReporter run(Path... files) { + return this.run((engine) -> { + }, files); + } + + @Nonnull + public BugCollectionBugReporter run(Consumer engineCustomization, Path... files) { DetectorFactoryCollection.resetInstance(new DetectorFactoryCollection()); try (FindBugs2 engine = new FindBugs2(); Project project = createProject(files)) { @@ -102,6 +110,7 @@ public BugCollectionBugReporter run(Path... files) { preferences.enableAllDetectors(true); engine.setUserPreferences(preferences); + engineCustomization.accept(engine); try { engine.execute(); } catch (final IOException | InterruptedException e) { diff --git a/test-harness/src/main/java/edu/umd/cs/findbugs/test/SpotBugsRule.java b/test-harness/src/main/java/edu/umd/cs/findbugs/test/SpotBugsRule.java index e597e27a05b..b98048941af 100644 --- a/test-harness/src/main/java/edu/umd/cs/findbugs/test/SpotBugsRule.java +++ b/test-harness/src/main/java/edu/umd/cs/findbugs/test/SpotBugsRule.java @@ -1,10 +1,12 @@ package edu.umd.cs.findbugs.test; import java.nio.file.Path; +import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import edu.umd.cs.findbugs.IFindBugsEngine; import org.junit.rules.ExternalResource; import edu.umd.cs.findbugs.BugCollection; @@ -76,16 +78,33 @@ public SpotBugsRule addAuxClasspathEntry(Path path) { *

* Run SpotBugs under given condition, and return its result. *

+ * @param engineCustomization + * A customization of the engine to apply before running engine#execute * @param paths * Paths of target class files * @return a {@link BugCollection} which contains all detected bugs. */ // TODO let users specify SlashedClassName, then find its file path automatically @Nonnull - public BugCollection performAnalysis(Path... paths) { + public BugCollection performAnalysis(Consumer engineCustomization, Path... paths) { if (runner == null) { throw new IllegalStateException("Please call this performAnalysis() method in test method"); } - return runner.run(paths).getBugCollection(); + return runner.run(engineCustomization, paths).getBugCollection(); + } + + /** + *

+ * Run SpotBugs under given condition, and return its result. + *

+ * @param paths + * Paths of target class files + * @return a {@link BugCollection} which contains all detected bugs. + */ + // TODO let users specify SlashedClassName, then find its file path automatically + @Nonnull + public BugCollection performAnalysis(Path... paths) { + return performAnalysis(e -> { + }, paths); } }