Skip to content

Commit 33e0fff

Browse files
authored
Merge pull request #990 from forcedotcom/dev
RELEASE: @W-12600174@: Merging `dev` to `release` for 3.10.0
2 parents c84662c + 5edd99c commit 33e0fff

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1780
-588
lines changed

messages/run-dfa.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "@salesforce/sfdx-scanner",
33
"description": "Static code scanner that applies quality and security rules to Apex code, and provides feedback.",
4-
"version": "3.9.0",
4+
"version": "3.10.0",
55
"author": "ISV SWAT",
66
"bugs": "https://github.com/forcedotcom/sfdx-scanner/issues",
77
"dependencies": {
88
"@babel/core": "^7.11.0",
99
"@babel/eslint-parser": "^7",
10+
"@eslint/js": "^8.35.0",
1011
"@lwc/eslint-plugin-lwc": "^1.1.2",
1112
"@oclif/command": "^1",
1213
"@oclif/config": "^1",
@@ -19,7 +20,7 @@
1920
"@typescript-eslint/parser": "^5.14.0",
2021
"cross-spawn": "^7.0.3",
2122
"csv-stringify": "^6.0.5",
22-
"eslint": "^8.10.0",
23+
"eslint": "^8.35.0",
2324
"eslint-plugin-import": "^2.25.4",
2425
"eslint-plugin-jest": "^26.1.1",
2526
"find-java-home": "1.2.2",
@@ -75,7 +76,7 @@
7576
"@types/uuid": "^8.3.4",
7677
"chai": "^4",
7778
"cross-env": "^7.0.3",
78-
"eslint": "^8.10.0",
79+
"eslint": "^8.35.0",
7980
"mocha": "^9",
8081
"mocha-junit-reporter": "^2.0.0",
8182
"nyc": "^15.0.0",

pmd-cataloger/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ group = "sfdx"
99
version = "1.0"
1010

1111
val distDir = "$buildDir/../../dist"
12-
val pmdVersion = "6.53.0"
12+
val pmdVersion = "6.54.0"
1313
val pmdFile = "pmd-bin-$pmdVersion.zip"
1414
val pmdUrl = "https://github.com/pmd/pmd/releases/download/pmd_releases%2F${pmdVersion}/${pmdFile}"
1515
val skippableJarRegexes = setOf("""^common_[\d\.-]*\.jar""".toRegex(),

retire-js/RetireJsVulns.json

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2834,7 +2834,7 @@
28342834
{
28352835
"below": "1.12.1",
28362836
"atOrAbove": "1.3.2",
2837-
"severity": "High",
2837+
"severity": "high",
28382838
"identifiers": {
28392839
"summary": " vulnerable to Arbitrary Code Injection via the template function",
28402840
"CVE": [
@@ -3836,6 +3836,34 @@
38363836
]
38373837
}
38383838
},
3839+
"chart.js": {
3840+
"vulnerabilities": [
3841+
{
3842+
"below": "2.9.4",
3843+
"severity": "high",
3844+
"identifiers": {
3845+
"summary": "Prototype pollution in chart.js",
3846+
"CVE": [
3847+
"CVE-2020-7746"
3848+
]
3849+
},
3850+
"info": [
3851+
"https://github.com/advisories/GHSA-h68q-55jf-x68w"
3852+
]
3853+
}
3854+
],
3855+
"extractors": {
3856+
"uri": [
3857+
"/Chart.js/(§§version§§)/chart(\\.min)?\\.js",
3858+
"/Chart.js/(§§version§§)/Chart.bundle(\\.min)?\\.js"
3859+
],
3860+
"filecontent": [
3861+
"var version=\"(§§version§§)\";const KNOWN_POSITIONS=\\[\"top\",\"bottom\",\"left\",\"right\",\"chartArea\"\\]",
3862+
"/\\*![\\s]+\\* Chart.js v(§§version§§)",
3863+
"/\\*![\\s]+\\* Chart.js[\\s]+\\* http://chartjs.org/[\\s]+\\* Version: (§§version§§)"
3864+
]
3865+
}
3866+
},
38393867
"dont check": {
38403868
"extractors": {
38413869
"uri": [

sfge/src/main/java/com/salesforce/config/EnvUtil.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.salesforce.config;
22

33
import com.google.common.annotations.VisibleForTesting;
4+
import com.salesforce.graph.ops.registry.RegistryDataLimitCalculator;
45
import java.util.concurrent.TimeUnit;
56

67
public final class EnvUtil {
@@ -11,6 +12,8 @@ public final class EnvUtil {
1112
private static final String ENV_IGNORE_PARSE_ERRORS = "SFGE_IGNORE_PARSE_ERRORS";
1213
private static final String ENV_LOG_WARNINGS_ON_VERBOSE = "SFGE_LOG_WARNINGS_ON_VERBOSE";
1314
private static final String ENV_PROGRESS_INCREMENTS = "SFGE_PROGRESS_INCREMENTS";
15+
private static final String ENV_STACK_DEPTH_LIMIT = "SFGE_STACK_DEPTH_LIMIT";
16+
private static final String ENV_PATH_EXPANSION_LIMIT = "SFGE_PATH_EXPANSION_LIMIT";
1417

1518
// TODO: These should move to SfgeConfigImpl and this class should return Optionals
1619
@VisibleForTesting
@@ -22,10 +25,16 @@ public final class EnvUtil {
2225
TimeUnit.MILLISECONDS.convert(15, TimeUnit.MINUTES);
2326

2427
@VisibleForTesting static final boolean DEFAULT_RULE_DISABLE_WARNING_VIOLATION = false;
25-
@VisibleForTesting static final boolean DEFAULT_IGNORE_PARSE_ERRORS = false;
2628
@VisibleForTesting static final boolean DEFAULT_LOG_WARNINGS_ON_VERBOSE = false;
2729
@VisibleForTesting static final int DEFAULT_PROGRESS_INCREMENTS = 10;
2830

31+
/** Artificial stack depth limit to keep path expansion under control. */
32+
@VisibleForTesting static final int DEFAULT_STACK_DEPTH_LIMIT = 450;
33+
34+
@VisibleForTesting
35+
static final int DEFAULT_PATH_EXPANSION_LIMIT =
36+
RegistryDataLimitCalculator.getApexPathExpanderRegistryLimit();
37+
2938
/**
3039
* Returns the value of the {@link #ENV_RULE_THREAD_COUNT} environment variable if set, else
3140
* {@link #DEFAULT_RULE_THREAD_COUNT}. Should be used to set the number of threads that can be
@@ -76,6 +85,22 @@ static int getProgressIncrements() {
7685
return getIntOrDefault(ENV_PROGRESS_INCREMENTS, DEFAULT_PROGRESS_INCREMENTS);
7786
}
7887

88+
/**
89+
* Returns stack depth limit upto which Graph Engine attempts to dig. Depths beyond this have a
90+
* high probability of throwing a StackOverFlow exception.
91+
*/
92+
static int getStackDepthLimit() {
93+
return getIntOrDefault(ENV_STACK_DEPTH_LIMIT, DEFAULT_STACK_DEPTH_LIMIT);
94+
}
95+
96+
/**
97+
* @return Maximum limit that items in registry can reach. Checks for env variable and returns
98+
* default when not set.
99+
*/
100+
static int getPathExpansionLimit() {
101+
return getIntOrDefault(ENV_PATH_EXPANSION_LIMIT, DEFAULT_PATH_EXPANSION_LIMIT);
102+
}
103+
79104
private static int getIntOrDefault(String name, int defaultValue) {
80105
String strVal = System.getProperty(name);
81106
return strVal == null ? defaultValue : Integer.parseInt(strVal);

sfge/src/main/java/com/salesforce/config/SfgeConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,10 @@ public interface SfgeConfig {
2525
* provided
2626
*/
2727
int getProgressIncrements();
28+
29+
/** Stack depth upto which Graph Engine attempts to walk. */
30+
int getStackDepthLimit();
31+
32+
/** Limit to control the growth of path expansion to help alleviate OutOfMemoryError. */
33+
int getPathExpansionLimit();
2834
}

sfge/src/main/java/com/salesforce/config/SfgeConfigImpl.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ public int getProgressIncrements() {
3030
return EnvUtil.getProgressIncrements();
3131
}
3232

33+
@Override
34+
public int getStackDepthLimit() {
35+
return EnvUtil.getStackDepthLimit();
36+
}
37+
38+
@Override
39+
public int getPathExpansionLimit() {
40+
return EnvUtil.getPathExpansionLimit();
41+
}
42+
3343
static SfgeConfigImpl getInstance() {
3444
return SfgeConfigImpl.LazyHolder.INSTANCE;
3545
}

sfge/src/main/java/com/salesforce/config/UserFacingMessages.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public static final class RuleViolationTemplates {
2020
// Format: First %s is either "abstract class" or "interface".
2121
// Second %s is the name of a class or interface.
2222
public static final String UNIMPLEMENTED_TYPE_RULE = "Extend, implement, or delete %s %s";
23+
public static final String LIMIT_REACHED_VIOLATION_MESSAGE =
24+
"%s. The analysis preemptively stopped running on this path to prevent an OutOfMemory error. Rerun Graph Engine targeting this entry method with a larger heap space.";
2325
}
2426

2527
/** Main args and process checks * */
@@ -37,7 +39,10 @@ public static final class RuleViolationTemplates {
3739
"Remove unreachable code to proceed with the analysis: %s,%s:%d";
3840

3941
public static final String VARIABLE_DECLARED_MULTIPLE_TIMES =
40-
"Rename or remove reused variable to proceed with analysis: %s,%s:%d";
42+
"This variable is reused. Rename or delete it to proceed with the analysis: %s,%s:%d";
43+
44+
public static final String INSUFFICIENT_HEAP_SPACE =
45+
"There's insufficient heap space (%d bytes) to execute Graph Engine. Increase heap space using --sfgejvmargs option and retry.";
4146

4247
public static final String STRIP_INACCESSIBLE_READ_WARNING_TEMPLATE =
4348
"For stripInaccessible checks on READ operation, Salesforce Graph Engine can't verify that only sanitized data is used after the check. Discard unsanitized data for [%2$s].";
@@ -51,7 +56,11 @@ public static final class RuleViolationTemplates {
5156

5257
public static final String INVALID_SYNTAX_TEMPLATE = "Invalid syntax at %d:%d. (%s)";
5358

54-
public static final String FIX_COMPILATION_ERRORS = "Fix compilation errors in %s and retry";
59+
public static final String FIX_COMPILATION_ERRORS =
60+
"Graph engine encountered compilation errors. Fix the errors in %s and retry.";
5561

5662
public static final String EXCEPTION_FORMAT_TEMPLATE = "%s, Caused by:\n%s";
63+
64+
public static final String PATH_EXPANSION_LIMIT_REACHED =
65+
"Graph Engine reached the path expansion upper limit (%d).";
5766
}

sfge/src/main/java/com/salesforce/graph/ApexPath.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
*/
4040
@NotThreadSafe
4141
@SuppressWarnings("PMD.NullAssignment")
42-
public final class ApexPath implements DeepCloneable<ApexPath>, Collectible<ApexPath> {
42+
public class ApexPath implements DeepCloneable<ApexPath>, Collectible<ApexPath> {
4343
public static final NullCollectible<ApexPath> NULL_VALUE =
4444
new NullCollectible<>(ApexPath.class);
4545

sfge/src/main/java/com/salesforce/graph/ops/expander/ApexPathExpander.java

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.salesforce.Collectible;
44
import com.salesforce.collections.CollectionUtil;
5+
import com.salesforce.config.SfgeConfigProvider;
56
import com.salesforce.exception.ProgrammingException;
67
import com.salesforce.exception.SfgeInterruptedException;
78
import com.salesforce.exception.UnexpectedException;
@@ -71,10 +72,13 @@
7172
* into {@link ApexPathCollapser} in order to provide information which may also result in the
7273
* current path getting collapsed.
7374
*/
74-
final class ApexPathExpander
75+
class ApexPathExpander
7576
implements ClassStaticScopeProvider, EngineDirectiveContextProvider, Registrable {
7677
private static final Logger LOGGER = LogManager.getLogger(ApexPathExpander.class);
7778

79+
/** Allowed stack depth limit */
80+
public final int stackDepthLimit;
81+
7882
/** Used to give each object a unique id */
7983
private static final AtomicLong ID_GENERATOR = new AtomicLong();
8084

@@ -92,6 +96,8 @@ final class ApexPathExpander
9296
/** Dynamically generated id used to establish object equality */
9397
private final Long id;
9498

99+
private int stackDepth;
100+
95101
/**
96102
* The vertex that caused a {@link MethodPathForkedException} to be thrown and the ForkEvent
97103
* that was included in the exception. This ForkEvent creates a common ancestry for all
@@ -195,6 +201,8 @@ final class ApexPathExpander
195201
this.topMostPath = new Stack<>();
196202
this.topMostPath.push(topMostPath);
197203
this.config = config;
204+
this.stackDepthLimit = SfgeConfigProvider.get().getStackDepthLimit();
205+
this.stackDepth = 0;
198206
this.symbolProviderVisitor =
199207
new DefaultSymbolProviderVertexVisitor(
200208
g, config.instantiateClassScope(g).orElse(null));
@@ -242,6 +250,10 @@ final class ApexPathExpander
242250
this.topMostPath = CloneUtil.cloneStack(other.topMostPath);
243251
this.config = CloneUtil.cloneImmutable(other.config);
244252

253+
this.stackDepthLimit = SfgeConfigProvider.get().getStackDepthLimit();
254+
// Reset stack depth
255+
this.stackDepth = 0;
256+
245257
// Find the method call that caused the fork and hook up the path
246258
BaseSFVertex topLevelVertex = ex.getTopLevelVertex();
247259
InvocableVertex invocable = ex.getInvocable();
@@ -641,12 +653,16 @@ public void visit(AbstractPathBasedRule rule) {
641653
}
642654
}
643655

656+
// Increment stack depth before visiting a method. Decrement stack depth when returning.
657+
incrementStackDepth(vertex);
644658
visit(methodPath);
659+
decrementStackDepth(vertex);
645660

646661
if (afterMethodCalled.add(pathInvocableCall)) {
647662
Optional<ApexValue<?>> lastReturnValue =
648663
symbolProviderVisitor.afterMethodCall(
649664
invocable, methodPath.getMethodVertex().get());
665+
650666
if (LOGGER.isTraceEnabled()) {
651667
LOGGER.trace(
652668
"lastReturnValue="
@@ -803,6 +819,26 @@ private Optional<ApexPath> resolveMethodCall(ApexPath path, InvocableVertex invo
803819
return result;
804820
}
805821

822+
private void incrementStackDepth(BaseSFVertex vertex) {
823+
if (LOGGER.isDebugEnabled()) {
824+
LOGGER.debug("Incrementing stack depth (" + stackDepth + ") for vertex: " + vertex);
825+
}
826+
stackDepth++;
827+
if (stackDepth > stackDepthLimit) {
828+
throw new StackDepthLimitExceededException(stackDepth, vertex);
829+
}
830+
}
831+
832+
private void decrementStackDepth(BaseSFVertex vertex) {
833+
if (LOGGER.isDebugEnabled()) {
834+
LOGGER.debug("Decrementing stack depth (" + stackDepth + ")");
835+
}
836+
stackDepth--;
837+
if (stackDepth < 0) {
838+
throw new UnexpectedException("Stack depth cannot be less than 0. vertex=" + vertex);
839+
}
840+
}
841+
806842
@Override
807843
public boolean equals(Object o) {
808844
if (this == o) return true;

0 commit comments

Comments
 (0)