Skip to content

Commit 74edb8f

Browse files
authored
Visit parents of Lambda classes to catch potential inherited random generators (#23)
1 parent 15429f0 commit 74edb8f

10 files changed

Lines changed: 134 additions & 1 deletion

File tree

src/main/java/software/amazon/lambda/snapstart/ByteCodeIntrospector.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import edu.umd.cs.findbugs.ba.XMethod;
99
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
1010
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
11+
import edu.umd.cs.findbugs.classfile.Global;
1112
import edu.umd.cs.findbugs.classfile.FieldDescriptor;
1213
import edu.umd.cs.findbugs.classfile.Global;
1314
import org.apache.bcel.generic.Type;
@@ -40,6 +41,7 @@ public class ByteCodeIntrospector {
4041
put("java.lang.System", setOf("currentTimeMillis", "nanoTime"));
4142
}};
4243

44+
private LambdaHandlerParentsDatabase lambdaHandlerParentsDatabase;
4345
private LambdaHandlerFieldsDatabase database;
4446

4547
private static Set<String> setOf(String ... strings) {
@@ -109,6 +111,11 @@ boolean implementsLambdaInterface(XClass xClass) {
109111
return false;
110112
}
111113

114+
boolean isLambdaHandlerParentClass(XClass xClass) {
115+
lambdaHandlerParentsDatabase = Global.getAnalysisCache().getDatabase(LambdaHandlerParentsDatabase.class);
116+
return lambdaHandlerParentsDatabase.getParentClasses().contains(xClass.toString());
117+
}
118+
112119
/**
113120
* This returns true only when the class directly implements
114121
* <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html">Java Functional Interface</a>.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package software.amazon.lambda.snapstart;
2+
3+
import edu.umd.cs.findbugs.BugReporter;
4+
import edu.umd.cs.findbugs.Detector;
5+
import edu.umd.cs.findbugs.ba.ClassContext;
6+
import edu.umd.cs.findbugs.ba.XClass;
7+
import org.apache.bcel.classfile.JavaClass;
8+
import edu.umd.cs.findbugs.classfile.Global;
9+
10+
import java.util.Objects;
11+
12+
13+
public class CacheLambdaHandlerParentClasses implements Detector {
14+
15+
private final ByteCodeIntrospector introspector;
16+
private ClassContext classContext;
17+
private XClass xClass;
18+
private final LambdaHandlerParentsDatabase database;
19+
20+
public CacheLambdaHandlerParentClasses(BugReporter bugReporter) {
21+
this.introspector = new ByteCodeIntrospector();
22+
database = new LambdaHandlerParentsDatabase();
23+
Global.getAnalysisCache().eagerlyPutDatabase(LambdaHandlerParentsDatabase.class, database);
24+
}
25+
26+
@Override
27+
public void visitClassContext(ClassContext classContext) {
28+
this.classContext = classContext;
29+
this.xClass = classContext.getXClass();
30+
if (introspector.isLambdaHandler(xClass)) {
31+
JavaClass[] parentClasses = null;
32+
try {
33+
parentClasses = classContext.getJavaClass().getSuperClasses();
34+
} catch (ClassNotFoundException e) {
35+
// Do nothing
36+
}
37+
38+
if (Objects.nonNull(parentClasses)) {
39+
for (JavaClass parentClass : parentClasses) {
40+
if (!parentClass.getClassName().equals("java.lang.Object")) {
41+
database.addLambdaParentClass(parentClass.getClassName().replace(".", "/"));
42+
}
43+
}
44+
}
45+
}
46+
}
47+
48+
@Override
49+
public void report() {
50+
// this is a non-reporting detector
51+
}
52+
}

src/main/java/software/amazon/lambda/snapstart/LambdaHandlerInitedWithRandomValue.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class LambdaHandlerInitedWithRandomValue extends OpcodeStackDetector {
2424

2525
private final BugReporter bugReporter;
2626
private boolean isLambdaHandlerClass;
27+
private boolean isLambdaHandlerParentClass;
2728
private boolean implementsFunctionalInterface;
2829
private boolean isLambdaHandlerField;
2930
private boolean isCracResource;
@@ -36,6 +37,7 @@ public class LambdaHandlerInitedWithRandomValue extends OpcodeStackDetector {
3637
public LambdaHandlerInitedWithRandomValue(BugReporter bugReporter) {
3738
this.bugReporter = bugReporter;
3839
this.isLambdaHandlerClass = false;
40+
this.isLambdaHandlerParentClass = false;
3941
this.implementsFunctionalInterface = false;
4042
this.isLambdaHandlerField = false;
4143
this.isCracResource = false;
@@ -52,6 +54,7 @@ public void visit(JavaClass obj) {
5254
inCracBeforeCheckpoint = false;
5355
XClass xClass = getXClass();
5456
isLambdaHandlerClass = introspector.isLambdaHandler(xClass);
57+
isLambdaHandlerParentClass = introspector.isLambdaHandlerParentClass(xClass);
5558
implementsFunctionalInterface = introspector.implementsFunctionalInterface(xClass);
5659
isLambdaHandlerField = introspector.isLambdaHandlerField(xClass);
5760
isCracResource = introspector.isCracResource(xClass);
@@ -60,7 +63,7 @@ public void visit(JavaClass obj) {
6063
@Override
6164
public boolean shouldVisitCode(Code code) {
6265
boolean shouldVisit = false;
63-
if (isLambdaHandlerClass || implementsFunctionalInterface || isLambdaHandlerField) {
66+
if (isLambdaHandlerClass || implementsFunctionalInterface || isLambdaHandlerField || isLambdaHandlerParentClass) {
6467
inStaticInitializer = getMethodName().equals(Const.STATIC_INITIALIZER_NAME);
6568
inInitializer = getMethodName().equals(Const.CONSTRUCTOR_NAME);
6669
database = Global.getAnalysisCache().getDatabase(ReturnValueRandomnessPropertyDatabase.class);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package software.amazon.lambda.snapstart;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
public class LambdaHandlerParentsDatabase {
7+
8+
private final List<String> parentClasses = new ArrayList<>();
9+
10+
public List<String> getParentClasses() {
11+
return this.parentClasses;
12+
}
13+
14+
public void addLambdaParentClass(String parentClass) {
15+
this.parentClasses.add(parentClass);
16+
}
17+
}

src/main/resources/findbugs.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,16 @@
2020
<Earlier class="software.amazon.lambda.snapstart.CacheLambdaHandlerFields"/>
2121
<Later class="software.amazon.lambda.snapstart.LambdaHandlerInitedWithRandomValue"/>
2222
</SplitPass>
23+
<SplitPass>
24+
<Earlier class="software.amazon.lambda.snapstart.CacheLambdaHandlerParentClasses"/>
25+
<Later class="software.amazon.lambda.snapstart.LambdaHandlerInitedWithRandomValue"/>
26+
</SplitPass>
2327
</OrderingConstraints>
2428

2529
<Detector class="software.amazon.lambda.snapstart.BuildRandomReturningMethodsDatabase"
2630
speed="fast" reports="" disabled="false" hidden="true"/>
31+
<Detector class="software.amazon.lambda.snapstart.CacheLambdaHandlerParentClasses"
32+
speed="fast" reports="" disabled="false" hidden="true"/>
2733
<Detector class="software.amazon.lambda.snapstart.CacheLambdaHandlerFields"
2834
speed="fast" reports="" disabled="false" hidden="true"/>
2935
<Detector class="software.amazon.lambda.snapstart.LambdaHandlerInitedWithRandomValue"

src/main/resources/messages.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
Detector that stores all the fields of the Lambda Handler class to be visited later.
1919
</Details>
2020
</Detector>
21+
22+
<Detector class="software.amazon.lambda.snapstart.CacheLambdaHandlerParentClasses">
23+
<Details>
24+
Detector that stores parent classes of Lambda Handler classes to be visited later.
25+
</Details>
26+
</Detector>
2127

2228
<Detector class="software.amazon.lambda.snapstart.LambdaHandlerInitedWithRandomValue">
2329
<Details>

src/test/java/software/amazon/lambda/snapstart/LambdaHandlerInitedWithRandomValueTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ public void testLambdaWithToString() {
152152
assertThat(bugCollection, containsExactly(1, snapStartBugMatcher().inClass("LambdaWithToString").atField("random").atLine(11).build()));
153153
}
154154

155+
@Test
156+
public void testLambdaWithParentClass() {
157+
BugCollection bugCollection = findBugsInClasses("LambdaWithParentClass", "ParentHandler", "SuperParentHandler");
158+
assertThat(bugCollection, containsExactly(1, snapStartBugMatcher().inClass("ParentHandler").atField("parentId").atLine(6).build()));
159+
assertThat(bugCollection, containsExactly(1, snapStartBugMatcher().inClass("SuperParentHandler").atField("superParentId").atLine(6).build()));
160+
}
161+
155162
@Test
156163
public void testClassImplementingFunctionalInterface() {
157164
BugCollection bugCollection = findBugsInClasses("ImplementsFunctionalInterface");
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package software.amazon.lambda.snapstart.lambdaexamples;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
6+
import java.util.logging.Level;
7+
import java.util.logging.Logger;
8+
9+
public class LambdaWithParentClass extends ParentHandler implements RequestHandler<String, String> {
10+
11+
@Override
12+
public String handleRequest(String s, Context context) {
13+
Logger logger = Logger.getLogger("LambdaWithParentClass");
14+
logger.log(Level.INFO, superParentId.toString());
15+
return parentId.toString();
16+
}
17+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package software.amazon.lambda.snapstart.lambdaexamples;
2+
3+
import java.util.UUID;
4+
5+
public abstract class ParentHandler extends SuperParentHandler {
6+
protected final UUID parentId = UUID.randomUUID();
7+
8+
protected ParentHandler() {}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package software.amazon.lambda.snapstart.lambdaexamples;
2+
3+
import java.util.UUID;
4+
5+
public class SuperParentHandler {
6+
protected final UUID superParentId = UUID.randomUUID();
7+
8+
protected SuperParentHandler() {}
9+
}

0 commit comments

Comments
 (0)