Skip to content

Commit 214480a

Browse files
authored
Merge pull request #857 from github/lcartey/lambda-equivalence-performance
`A5-1-9`: Improve performance, address duplication
2 parents 4ac7c5c + a74c8a9 commit 214480a

File tree

5 files changed

+53
-21
lines changed

5 files changed

+53
-21
lines changed

c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import cpp
1515
import codingstandards.c.cert
1616
import codingstandards.cpp.Macro
1717
import codingstandards.cpp.SideEffect
18-
import codingstandards.cpp.StructuralEquivalence
1918
import codingstandards.cpp.sideeffect.DefaultEffects
2019
import codingstandards.cpp.sideeffect.Customizations
2120
import semmle.code.cpp.valuenumbering.HashCons
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `A5-1-9` - `IdenticalLambdaExpressions.ql`:
2+
- Performance has been improved.
3+
- False positives due to repeated invocation of macros containing lambdas have been excluded.

cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql

+9-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ where
2424
not lambdaExpression = otherLambdaExpression and
2525
not lambdaExpression.isFromTemplateInstantiation(_) and
2626
not otherLambdaExpression.isFromTemplateInstantiation(_) and
27-
getLambdaHashCons(lambdaExpression) = getLambdaHashCons(otherLambdaExpression)
27+
getLambdaHashCons(lambdaExpression) = getLambdaHashCons(otherLambdaExpression) and
28+
// Do not report lambdas produced by the same macro in different invocations
29+
not exists(Macro m, MacroInvocation m1, MacroInvocation m2 |
30+
m1 = m.getAnInvocation() and
31+
m2 = m.getAnInvocation() and
32+
not m1 = m2 and // Lambdas in the same macro can be reported
33+
m1.getAnExpandedElement() = lambdaExpression and
34+
m2.getAnExpandedElement() = otherLambdaExpression
35+
)
2836
select lambdaExpression, "Lambda expression is identical to $@ lambda expression.",
2937
otherLambdaExpression, "this"

cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll

+34-18
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ private module HashCons {
211211

212212
private newtype HC_Params =
213213
HC_NoParams() or
214-
HC_ParamCons(HashConsExpr hc, int i, HC_Params list) { mk_ParamCons(hc, i, list, _) }
214+
HC_ParamCons(Type t, string name, int i, HC_Params list) { mk_ParamCons(t, name, i, list, _) }
215215

216216
/**
217217
* HashConsExpr is the hash-cons of an expression. The relationship between `Expr`
@@ -624,11 +624,21 @@ private module HashCons {
624624
strictcount(access.getTarget()) = 1
625625
}
626626

627+
/**
628+
* Gets the name of a variable.
629+
*
630+
* Extracted for performance reasons, to avoid magic, which was causing performance issues in getParameter(int i).
631+
*/
632+
pragma[nomagic]
633+
private string getVariableName(Variable v) { result = v.getName() }
634+
627635
/* Note: This changed from the original HashCons module to be able to find structural equivalent expression. */
628636
private predicate mk_Variable(Type t, string name, VariableAccess access) {
629637
analyzableVariable(access) and
630638
exists(Variable v |
631-
v = access.getTarget() and t = v.getUnspecifiedType() and name = v.getName()
639+
v = access.getTarget() and
640+
t = v.getUnspecifiedType() and
641+
name = getVariableName(v)
632642
)
633643
}
634644

@@ -1104,7 +1114,14 @@ private module HashCons {
11041114
nee.getExpr().getFullyConverted() = child.getAnExpr()
11051115
}
11061116

1107-
private predicate mk_StmtCons(HashConsStmt hc, int i, HC_Stmts list, BlockStmt block) {
1117+
private class LambdaBlockStmt extends BlockStmt {
1118+
LambdaBlockStmt() {
1119+
// Restricting to statements inside a lambda expressions.
1120+
this.getParentScope*() = any(LambdaExpression le).getLambdaFunction()
1121+
}
1122+
}
1123+
1124+
private predicate mk_StmtCons(HashConsStmt hc, int i, HC_Stmts list, LambdaBlockStmt block) {
11081125
hc = hashConsStmt(block.getStmt(i)) and
11091126
(
11101127
exists(HashConsStmt head, HC_Stmts tail |
@@ -1118,13 +1135,13 @@ private module HashCons {
11181135
}
11191136

11201137
private predicate mk_StmtConsInner(
1121-
HashConsStmt head, HC_Stmts tail, int i, HC_Stmts list, BlockStmt block
1138+
HashConsStmt head, HC_Stmts tail, int i, HC_Stmts list, LambdaBlockStmt block
11221139
) {
11231140
list = HC_StmtCons(head, i, tail) and
11241141
mk_StmtCons(head, i, tail, block)
11251142
}
11261143

1127-
private predicate mk_BlockStmtCons(HC_Stmts hc, BlockStmt s) {
1144+
private predicate mk_BlockStmtCons(HC_Stmts hc, LambdaBlockStmt s) {
11281145
if s.getNumStmt() > 0
11291146
then
11301147
exists(HashConsStmt head, HC_Stmts tail |
@@ -1275,24 +1292,25 @@ private module HashCons {
12751292
mk_DeclConsInner(_, _, s.getNumDeclarations() - 1, hc, s)
12761293
}
12771294

1278-
private predicate mk_ParamCons(HashConsExpr hc, int i, HC_Params list, Function f) {
1279-
hc = hashConsExpr(f.getParameter(i).getAnAccess()) and
1280-
(
1281-
exists(HashConsExpr head, HC_Params tail |
1282-
mk_ParamConsInner(head, tail, i - 1, list, f) and
1283-
i > 0
1284-
)
1295+
private predicate mk_ParamCons(Type t, string name, int i, HC_Params list, Function f) {
1296+
exists(Parameter p |
1297+
p = f.getParameter(i) and
1298+
t = p.getType() and
1299+
name = p.getName()
1300+
|
1301+
mk_ParamConsInner(_, _, _, i - 1, list, f) and
1302+
i > 0
12851303
or
12861304
i = 0 and
12871305
list = HC_NoParams()
12881306
)
12891307
}
12901308

12911309
private predicate mk_ParamConsInner(
1292-
HashConsExpr head, HC_Params tail, int i, HC_Params list, Function f
1310+
Type t, string name, HC_Params tail, int i, HC_Params list, Function f
12931311
) {
1294-
list = HC_ParamCons(head, i, tail) and
1295-
mk_ParamCons(head, i, tail, f)
1312+
list = HC_ParamCons(t, name, i, tail) and
1313+
mk_ParamCons(t, name, i, tail, f)
12961314
}
12971315

12981316
private predicate mk_FunctionCons(
@@ -1302,7 +1320,7 @@ private module HashCons {
13021320
name = f.getName() and
13031321
body = hashConsStmt(f.getBlock()) and
13041322
if f.getNumberOfParameters() > 0
1305-
then mk_ParamConsInner(_, _, f.getNumberOfParameters() - 1, params, f)
1323+
then mk_ParamConsInner(_, _, _, f.getNumberOfParameters() - 1, params, f)
13061324
else params = HC_NoParams()
13071325
}
13081326

@@ -1486,8 +1504,6 @@ private module HashCons {
14861504

14871505
cached
14881506
HashConsStmt hashConsStmt(Stmt s) {
1489-
// Restricting to statements inside a lambda expressions.
1490-
s.getParentScope*() = any(LambdaExpression le).getLambdaFunction() and
14911507
exists(HC_Stmts list |
14921508
mk_BlockStmtCons(list, s) and
14931509
result = HC_BlockStmt(list)

cpp/autosar/test/rules/A5-1-9/test.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,10 @@ class Test_issue468 {
104104
LogError("Error");
105105
LogFatal("Fatal");
106106
}
107-
};
107+
};
108+
109+
#define MACRO() [](int i) -> int { return i + 3; }
110+
void test_macros() {
111+
MACRO(); // COMPLIANT
112+
MACRO(); // COMPLIANT - no duplication
113+
}

0 commit comments

Comments
 (0)