Skip to content

Commit 33dfa65

Browse files
authored
Merge pull request #23022 from MathiasVP/replace-ql-models-with-mad-for-assoc-cleaned-up-step-3
C++: Speed up `forwards` logic
2 parents 1e3cc27 + dacd42a commit 33dfa65

1 file changed

Lines changed: 141 additions & 119 deletions

File tree

‎cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll‎

Lines changed: 141 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ module ConstructorForwarding {
12201220
(t1.isVolatile() implies t2.isVolatile())
12211221
}
12221222

1223+
bindingset[arg]
12231224
private predicate baseTypeCompatible(Type arg, Type param) {
12241225
param.stripTopLevelSpecifiers() = arg.stripTopLevelSpecifiers().(Class).getABaseClass+() and
12251226
preservesQualifiers(arg, param)
@@ -1229,6 +1230,7 @@ module ConstructorForwarding {
12291230

12301231
private predicate routineType(Type t) { t.stripTopLevelSpecifiers() instanceof RoutineType }
12311232

1233+
bindingset[arg]
12321234
private predicate pointerConversion(Cpp::PointerType arg, Cpp::PointerType param) {
12331235
exists(Type argBase, Type paramBase |
12341236
argBase = arg.getBaseType() and
@@ -1256,6 +1258,7 @@ module ConstructorForwarding {
12561258
t instanceof RoutineType
12571259
}
12581260

1261+
bindingset[t, category]
12591262
private predicate referenceAcceptsCategory(Cpp::ReferenceType t, ValueCategory category) {
12601263
if t instanceof Cpp::LValueReferenceType
12611264
then
@@ -1285,19 +1288,13 @@ module ConstructorForwarding {
12851288

12861289
private predicate isUnderlyingType(Type type) { type = type.getUnderlyingType() }
12871290

1288-
private newtype TTypeState =
1289-
MkTypeState(Type type, ValueCategory category, Boolean conversionUsed, Phase phase) {
1290-
not type instanceof Cpp::ReferenceType and
1291-
not type instanceof FunctionReferenceType and
1292-
isUnderlyingType(type)
1293-
}
1294-
12951291
private ValueCategory getCategoryForRef(Cpp::ReferenceType reference) {
12961292
reference instanceof Cpp::LValueReferenceType and result = LValue()
12971293
or
12981294
reference instanceof Cpp::RValueReferenceType and result = XValue()
12991295
}
13001296

1297+
bindingset[t]
13011298
private Type getValueType(Type t, ValueCategory category) {
13021299
result = t.(FunctionReferenceType).getBaseType().getUnderlyingType() and
13031300
category = LValue()
@@ -1311,71 +1308,33 @@ module ConstructorForwarding {
13111308
category = PRValue()
13121309
}
13131310

1314-
bindingset[arg, param]
1315-
pragma[inline_late]
1311+
bindingset[arg]
13161312
private predicate qualificationCompatible(Type arg, Type param) {
13171313
arg.stripTopLevelSpecifiers() = param.stripTopLevelSpecifiers() and
13181314
preservesQualifiers(arg, param)
13191315
}
13201316

1321-
private class TypeState extends TTypeState {
1322-
Type getType() { this = MkTypeState(result, _, _, _) }
1323-
1324-
ValueCategory getCategory() { this = MkTypeState(_, result, _, _) }
1325-
1326-
Phase getPhase() { this = MkTypeState(_, _, _, result) }
1327-
1328-
/** Holds if this state's phase permits a value or base-class conversion. */
1329-
predicate canConvertValue() {
1330-
this.getPhase() = Initial() or this.getPhase() = AfterTransformation()
1331-
}
1332-
1333-
predicate hasNotUsedConversion() { this = MkTypeState(_, _, false, _) }
1334-
1335-
string toString() { result = this.getType().toString() }
1336-
1337-
predicate isSource(Type argType) {
1338-
argType = getForwardedArgumentType(_, _, _) and
1339-
exists(ValueCategory category |
1340-
this = MkTypeState(getValueType(argType, category), category, false, Initial())
1341-
)
1342-
}
1343-
1344-
predicate matchesParameter(Type paramType) {
1345-
exists(Type base | base = paramType.(Cpp::ReferenceType).getBaseType() |
1346-
qualificationCompatible(this.getType(), base) and
1347-
referenceAcceptsCategory(paramType, this.getCategory())
1348-
)
1349-
or
1350-
not paramType instanceof Cpp::ReferenceType and
1351-
this.getType().stripTopLevelSpecifiers() = paramType.stripTopLevelSpecifiers()
1352-
}
1353-
1354-
predicate isSink(Type paramType, Cpp::Constructor constructor) {
1355-
paramType = getConstructorParameterType(constructor, _) and
1356-
this.matchesParameter(paramType)
1357-
}
1317+
bindingset[argType, category]
1318+
private predicate matchesParameter(Type argType, ValueCategory category, Type paramType) {
1319+
exists(Type base | base = paramType.(Cpp::ReferenceType).getBaseType() |
1320+
qualificationCompatible(argType, base) and
1321+
referenceAcceptsCategory(paramType, category)
1322+
)
1323+
or
1324+
not paramType instanceof Cpp::ReferenceType and
1325+
argType.stripTopLevelSpecifiers() = paramType.stripTopLevelSpecifiers()
13581326
}
13591327

13601328
private Cpp::PointerType pointerType(Type base) {
13611329
result.getBaseType() = base.getUnderlyingType()
13621330
}
13631331

1364-
private predicate arrayToPointerStep(TypeState argState, TypeState paramState) {
1365-
exists(Cpp::ArrayType array, boolean conversionUsed |
1366-
argState = MkTypeState(array, _, conversionUsed, Initial()) and
1367-
paramState =
1368-
MkTypeState(pointerType(array.getBaseType()), PRValue(), conversionUsed,
1369-
AfterTransformation())
1370-
)
1332+
private predicate arrayToPointerStep(Cpp::ArrayType array, Cpp::PointerType pointer) {
1333+
pointer = pointerType(array.getBaseType())
13711334
}
13721335

1373-
private predicate functionToPointerStep(TypeState argState, TypeState paramState) {
1374-
exists(RoutineType routine, FunctionPointerType pointer, boolean conversionUsed |
1375-
argState = MkTypeState(routine, _, conversionUsed, Initial()) and
1376-
routine = pointer.getBaseType().getUnderlyingType() and
1377-
paramState = MkTypeState(pointer, PRValue(), conversionUsed, AfterTransformation())
1378-
)
1336+
private predicate functionToPointerStep(RoutineType routine, FunctionPointerType pointer) {
1337+
routine = pointer.getBaseType().getUnderlyingType()
13791338
}
13801339

13811340
private predicate arithmeticConversion(Type t) {
@@ -1386,14 +1345,12 @@ module ConstructorForwarding {
13861345

13871346
private predicate hasNoTopLevelSpecifiers(Type type) { type = type.stripTopLevelSpecifiers() }
13881347

1389-
private predicate valueConversionStep(TypeState argState, TypeState paramState) {
1390-
exists(Type argType, Type paramType, boolean conversionUsed |
1391-
argState = MkTypeState(_, _, conversionUsed, _) and
1392-
argState.canConvertValue() and
1393-
argType = argState.getType().stripTopLevelSpecifiers() and
1348+
bindingset[type]
1349+
private predicate valueConversionStep(Type type, Type paramType) {
1350+
exists(Type argType |
1351+
argType = type.stripTopLevelSpecifiers() and
13941352
hasNoTopLevelSpecifiers(paramType) and
1395-
argType != paramType and
1396-
paramState = MkTypeState(paramType, PRValue(), conversionUsed, AfterValueConversion())
1353+
argType != paramType
13971354
|
13981355
paramType instanceof ArithmeticType and
13991356
arithmeticConversion(argType)
@@ -1420,86 +1377,151 @@ module ConstructorForwarding {
14201377
k = FunPtrKind()
14211378
}
14221379

1423-
private predicate pointerQualificationStep(TypeState argState, TypeState paramState) {
1424-
exists(Type argType, Type paramType, boolean conversionUsed, PtrKind k |
1425-
argState = MkTypeState(_, _, conversionUsed, _) and
1426-
argState.getPhase() != AfterQualification() and
1427-
argType = argState.getType().stripTopLevelSpecifiers() and
1380+
bindingset[type]
1381+
private predicate pointerQualificationStep(Type type, Type paramType) {
1382+
exists(Type argType, PtrKind k |
1383+
argType = type.stripTopLevelSpecifiers() and
14281384
hasNoTopLevelSpecifiers(paramType) and
14291385
argType != paramType and
1430-
qualificationCompatible(pointerBase(argType, k), pointerBase(paramType, k)) and
1431-
paramState = MkTypeState(paramType, PRValue(), conversionUsed, AfterQualification())
1386+
qualificationCompatible(pointerBase(argType, pragma[only_bind_into](k)),
1387+
pointerBase(paramType, pragma[only_bind_into](k)))
14321388
)
14331389
}
14341390

1435-
private predicate baseClassStep(TypeState argState, TypeState paramState) {
1436-
exists(Type arg, Type param, ValueCategory category, boolean conversionUsed |
1437-
argState = MkTypeState(arg, category, conversionUsed, _) and
1438-
argState.canConvertValue() and
1439-
baseTypeCompatible(arg, param) and
1440-
paramState = MkTypeState(param, category, conversionUsed, AfterValueConversion())
1441-
)
1391+
bindingset[argType]
1392+
private predicate baseClassStep(Type argType, Type paramType) {
1393+
baseTypeCompatible(argType, paramType)
14421394
}
14431395

1444-
private predicate convertingConstructorStep(TypeState argState, TypeState paramState) {
1396+
bindingset[argType, argCategory]
1397+
private predicate convertingConstructorStep(
1398+
Type argType, ValueCategory argCategory, Class paramType
1399+
) {
14451400
exists(ConvertingConstructor constructor |
1446-
argState.hasNotUsedConversion() and
1447-
argState.matchesParameter(constructor.getUnderlyingFromType()) and
1448-
paramState = MkTypeState(constructor.getDeclaringType(), PRValue(), true, Initial())
1401+
matchesParameter(argType, argCategory, constructor.getUnderlyingFromType()) and
1402+
paramType = constructor.getDeclaringType()
14491403
)
14501404
}
14511405

1452-
private predicate conversionOperatorStep(TypeState argState, TypeState paramState) {
1453-
exists(ConversionOperator conversion, ValueCategory category |
1406+
bindingset[argType]
1407+
private predicate conversionOperatorStep(Type argType, Type paramType, ValueCategory paramCategory) {
1408+
exists(ConversionOperator conversion |
14541409
not conversion.isFromUninstantiatedTemplate(_) and
14551410
not conversion.isExplicit() and
14561411
not conversion.isDeleted() and
1457-
argState.hasNotUsedConversion() and
1458-
conversion.getSourceType() =
1459-
argState.getType().stripTopLevelSpecifiers().(Class).getABaseClass*() and
1460-
paramState =
1461-
MkTypeState(getValueType(conversion.getDestType().getUnderlyingType(), category), category,
1462-
true, Initial())
1412+
conversion.getSourceType() = argType.stripTopLevelSpecifiers().(Class).getABaseClass*() and
1413+
paramType = getValueType(conversion.getDestType().getUnderlyingType(), paramCategory)
14631414
)
14641415
}
14651416

1466-
private predicate step(TypeState argState, TypeState paramState) {
1467-
arrayToPointerStep(argState, paramState)
1468-
or
1469-
functionToPointerStep(argState, paramState)
1470-
or
1471-
valueConversionStep(argState, paramState)
1472-
or
1473-
pointerQualificationStep(argState, paramState)
1474-
or
1475-
baseClassStep(argState, paramState)
1476-
or
1477-
convertingConstructorStep(argState, paramState)
1478-
or
1479-
conversionOperatorStep(argState, paramState)
1480-
}
1481-
1482-
private predicate typeFwd(TypeState state) {
1483-
state.isSource(_)
1417+
bindingset[argType, argCategory, argConversionUsed, argPhase]
1418+
pragma[inline_late]
1419+
private predicate typeStep(
1420+
Type argType, ValueCategory argCategory, boolean argConversionUsed, Phase argPhase,
1421+
Type paramType, ValueCategory paramCategory, boolean paramConversionUsed, Phase paramPhase
1422+
) {
1423+
paramConversionUsed = argConversionUsed and
1424+
(
1425+
argPhase = Initial() and
1426+
paramCategory = PRValue() and
1427+
paramPhase = AfterTransformation() and
1428+
(
1429+
arrayToPointerStep(argType, paramType)
1430+
or
1431+
functionToPointerStep(argType, paramType)
1432+
)
1433+
or
1434+
(argPhase = Initial() or argPhase = AfterTransformation()) and
1435+
paramPhase = AfterValueConversion() and
1436+
(
1437+
valueConversionStep(argType, paramType) and paramCategory = PRValue()
1438+
or
1439+
baseClassStep(argType, paramType) and paramCategory = argCategory
1440+
)
1441+
or
1442+
argPhase != AfterQualification() and
1443+
pointerQualificationStep(argType, paramType) and
1444+
paramCategory = PRValue() and
1445+
paramPhase = AfterQualification()
1446+
)
14841447
or
1485-
exists(TypeState previous |
1486-
typeFwd(previous) and
1487-
step(previous, state)
1448+
argConversionUsed = false and
1449+
paramConversionUsed = true and
1450+
paramPhase = Initial() and
1451+
(
1452+
convertingConstructorStep(argType, argCategory, paramType) and paramCategory = PRValue()
1453+
or
1454+
conversionOperatorStep(argType, paramType, paramCategory)
14881455
)
14891456
}
14901457

1491-
private predicate typeRev(TypeState state, Cpp::Constructor constructor) {
1492-
typeFwd(state) and
1458+
private predicate typeFwd(Type type, ValueCategory category, boolean conversionUsed, Phase phase) {
1459+
not type instanceof Cpp::ReferenceType and
1460+
not type instanceof FunctionReferenceType and
1461+
isUnderlyingType(type) and
14931462
(
1494-
state.isSink(_, constructor)
1463+
type = getValueType(getForwardedArgumentType(_, _, _), category) and
1464+
conversionUsed = false and
1465+
phase = Initial()
14951466
or
1496-
exists(TypeState next |
1497-
typeRev(next, constructor) and
1498-
step(state, next)
1467+
exists(
1468+
Type previousType, ValueCategory previousCategory, boolean previousConversionUsed,
1469+
Phase previousPhase
1470+
|
1471+
typeFwd(previousType, previousCategory, previousConversionUsed, previousPhase) and
1472+
typeStep(previousType, previousCategory, previousConversionUsed, previousPhase, type,
1473+
category, conversionUsed, phase)
14991474
)
15001475
)
15011476
}
15021477

1478+
private newtype TTypeState =
1479+
MkTypeState(Type type, ValueCategory category, Boolean conversionUsed, Phase phase) {
1480+
typeFwd(type, category, conversionUsed, phase)
1481+
}
1482+
1483+
private class TypeState extends TTypeState {
1484+
Type getType() { this = MkTypeState(result, _, _, _) }
1485+
1486+
ValueCategory getCategory() { this = MkTypeState(_, result, _, _) }
1487+
1488+
Phase getPhase() { this = MkTypeState(_, _, _, result) }
1489+
1490+
string toString() { result = this.getType().toString() }
1491+
1492+
predicate isSource(Type argType) {
1493+
argType = getForwardedArgumentType(_, _, _) and
1494+
exists(ValueCategory category |
1495+
this = MkTypeState(getValueType(argType, category), category, false, Initial())
1496+
)
1497+
}
1498+
1499+
predicate isSink(Type paramType, Cpp::Constructor constructor) {
1500+
paramType = getConstructorParameterType(constructor, _) and
1501+
matchesParameter(this.getType(), this.getCategory(), paramType)
1502+
}
1503+
}
1504+
1505+
private predicate step(TypeState argState, TypeState paramState) {
1506+
exists(
1507+
Type t1, Type t2, ValueCategory vc1, ValueCategory vc2, boolean b1, boolean b2, Phase p1,
1508+
Phase p2
1509+
|
1510+
argState = MkTypeState(t1, vc1, b1, p1) and
1511+
paramState = MkTypeState(t2, vc2, b2, p2) and
1512+
typeStep(t1, vc1, b1, p1, t2, vc2, b2, p2)
1513+
)
1514+
}
1515+
1516+
private predicate typeRev(TypeState state, Cpp::Constructor constructor) {
1517+
state.isSink(_, constructor)
1518+
or
1519+
exists(TypeState next |
1520+
typeRev(next, constructor) and
1521+
step(state, next)
1522+
)
1523+
}
1524+
15031525
private predicate prunedStep(TypeState argState, TypeState paramState) {
15041526
exists(Cpp::Constructor constructor |
15051527
typeRev(argState, constructor) and

0 commit comments

Comments
 (0)