Skip to content

Commit 42b90ed

Browse files
committed
C++: Hashcons for ?:, ExprCall, and weird stuff
1 parent 27040be commit 42b90ed

File tree

3 files changed

+180
-28
lines changed

3 files changed

+180
-28
lines changed

cpp/ql/src/semmle/code/cpp/valuenumbering/HashCons.qll

Lines changed: 150 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ private cached newtype HCBase =
8787
HC_NonmemberFunctionCall(Function fcn, HC_Args args) {
8888
mk_NonmemberFunctionCall(fcn, args, _)
8989
}
90+
or HC_ExprCall(HashCons hc, HC_Args args) {
91+
mk_ExprCall(hc, args, _)
92+
}
9093
or
9194
HC_MemberFunctionCall(Function trg, HashCons qual, HC_Args args) {
9295
mk_MemberFunctionCall(trg, qual, args, _)
@@ -107,6 +110,12 @@ private cached newtype HCBase =
107110
or
108111
HC_AlignofExpr(HashCons child) {mk_AlignofExpr(child, _)}
109112
or
113+
HC_UuidofOperator(Type t) {mk_UuidofOperator(t, _)}
114+
or
115+
HC_TypeidType(Type t) {mk_TypeidType(t, _)}
116+
or
117+
HC_TypeidExpr(HashCons child) {mk_TypeidExpr(child, _)}
118+
or
110119
HC_ClassAggregateLiteral(Class c, HC_Fields hcf) {
111120
mk_ClassAggregateLiteral(c, hcf, _)
112121
}
@@ -123,6 +132,14 @@ private cached newtype HCBase =
123132
or
124133
HC_ReThrowExpr()
125134
or
135+
HC_ConditionalExpr(HashCons cond, HashCons trueHC, HashCons falseHC) {
136+
mk_ConditionalExpr(cond, trueHC, falseHC, _)
137+
}
138+
or
139+
HC_NoExceptExpr(HashCons child) {
140+
mk_NoExceptExpr(child, _)
141+
}
142+
or
126143
// Any expression that is not handled by the cases above is
127144
// given a unique number based on the expression itself.
128145
HC_Unanalyzable(Expr e) { not analyzableExpr(e,_) }
@@ -153,11 +170,11 @@ private newtype HC_Align =
153170

154171
/** Used to implement hash-consing of argument lists */
155172
private newtype HC_Args =
156-
HC_EmptyArgs(Function fcn) {
173+
HC_EmptyArgs() {
157174
any()
158175
}
159-
or HC_ArgCons(Function fcn, HashCons hc, int i, HC_Args list) {
160-
mk_ArgCons(fcn, hc, i, list, _)
176+
or HC_ArgCons(HashCons hc, int i, HC_Args list) {
177+
mk_ArgCons(hc, i, list, _)
161178
}
162179

163180
/**
@@ -228,12 +245,18 @@ class HashCons extends HCBase {
228245
if this instanceof HC_SizeofExpr then result = "SizeofExprOperator" else
229246
if this instanceof HC_AlignofType then result = "AlignofTypeOperator" else
230247
if this instanceof HC_AlignofExpr then result = "AlignofExprOperator" else
248+
if this instanceof HC_UuidofOperator then result = "UuidofOperator" else
249+
if this instanceof HC_TypeidType then result = "TypeidType" else
250+
if this instanceof HC_TypeidExpr then result = "TypeidExpr" else
231251
if this instanceof HC_ArrayAggregateLiteral then result = "ArrayAggregateLiteral" else
232252
if this instanceof HC_ClassAggregateLiteral then result = "ClassAggreagateLiteral" else
233253
if this instanceof HC_DeleteExpr then result = "DeleteExpr" else
234254
if this instanceof HC_DeleteArrayExpr then result = "DeleteArrayExpr" else
235255
if this instanceof HC_ThrowExpr then result = "ThrowExpr" else
236256
if this instanceof HC_ReThrowExpr then result = "ReThrowExpr" else
257+
if this instanceof HC_ExprCall then result = "ExprCall" else
258+
if this instanceof HC_ConditionalExpr then result = "ConditionalExpr" else
259+
if this instanceof HC_NoExceptExpr then result = "NoExceptExpr" else
237260
result = "error"
238261
}
239262

@@ -473,19 +496,40 @@ private predicate mk_NonmemberFunctionCall(Function fcn, HC_Args args, FunctionC
473496
analyzableNonmemberFunctionCall(fc) and
474497
(
475498
exists(HashCons head, HC_Args tail |
476-
args = HC_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail) and
477-
mk_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail, fc)
499+
args = HC_ArgCons(head, fc.getNumberOfArguments() - 1, tail) and
500+
mk_ArgCons(head, fc.getNumberOfArguments() - 1, tail, fc)
478501
)
479502
or
480503
fc.getNumberOfArguments() = 0 and
481-
args = HC_EmptyArgs(fcn)
504+
args = HC_EmptyArgs()
505+
)
506+
}
507+
508+
private predicate analyzableExprCall(ExprCall ec) {
509+
forall(int i |
510+
exists(ec.getArgument(i)) |
511+
strictcount(ec.getArgument(i).getFullyConverted()) = 1
512+
) and
513+
strictcount(ec.getExpr().getFullyConverted()) = 1
514+
}
515+
516+
private predicate mk_ExprCall(HashCons hc, HC_Args args, ExprCall ec) {
517+
hc.getAnExpr() = ec.getExpr() and
518+
(
519+
exists(HashCons head, HC_Args tail |
520+
args = HC_ArgCons(head, ec.getNumberOfArguments() - 1, tail) and
521+
mk_ArgCons(head, ec.getNumberOfArguments() - 1, tail, ec)
522+
)
523+
or
524+
ec.getNumberOfArguments() = 0 and
525+
args = HC_EmptyArgs()
482526
)
483527
}
484528

485529
private predicate analyzableMemberFunctionCall(
486530
FunctionCall fc) {
487531
forall(int i |
488-
exists(fc.getArgument(i)) |
532+
exists(fc.getArgument(i)) |
489533
strictcount(fc.getArgument(i).getFullyConverted()) = 1
490534
) and
491535
strictcount(fc.getTarget()) = 1 and
@@ -503,40 +547,39 @@ private predicate mk_MemberFunctionCall(
503547
hashCons(fc.getQualifier().getFullyConverted()) = qual and
504548
(
505549
exists(HashCons head, HC_Args tail |
506-
args = HC_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail) and
507-
mk_ArgCons(fcn, head, fc.getNumberOfArguments() - 1, tail, fc)
550+
args = HC_ArgCons(head, fc.getNumberOfArguments() - 1, tail) and
551+
mk_ArgCons(head, fc.getNumberOfArguments() - 1, tail, fc)
508552
)
509553
or
510554
fc.getNumberOfArguments() = 0 and
511-
args = HC_EmptyArgs(fcn)
555+
args = HC_EmptyArgs()
512556
)
513557
}
514558

515-
private predicate analyzableFunctionCall(
516-
FunctionCall fc
517-
) {
518-
analyzableNonmemberFunctionCall(fc)
559+
private predicate analyzableCall(Call c) {
560+
analyzableNonmemberFunctionCall(c)
561+
or
562+
analyzableMemberFunctionCall(c)
519563
or
520-
analyzableMemberFunctionCall(fc)
564+
analyzableExprCall(c)
521565
}
522566

523567
/**
524568
* Holds if `fc` is a call to `fcn`, `fc`'s first `i` arguments have hash-cons
525569
* `list`, and `fc`'s argument at index `i` has hash-cons `hc`.
526570
*/
527-
private predicate mk_ArgCons(Function fcn, HashCons hc, int i, HC_Args list, FunctionCall fc) {
528-
analyzableFunctionCall(fc) and
529-
fc.getTarget() = fcn and
530-
hc = hashCons(fc.getArgument(i).getFullyConverted()) and
571+
private predicate mk_ArgCons(HashCons hc, int i, HC_Args list,Call c) {
572+
analyzableCall(c) and
573+
hc = hashCons(c.getArgument(i).getFullyConverted()) and
531574
(
532575
exists(HashCons head, HC_Args tail |
533-
list = HC_ArgCons(fcn, head, i - 1, tail) and
534-
mk_ArgCons(fcn, head, i - 1, tail, fc) and
576+
list = HC_ArgCons(head, i - 1, tail) and
577+
mk_ArgCons(head, i - 1, tail, c) and
535578
i > 0
536579
)
537580
or
538581
i = 0 and
539-
list = HC_EmptyArgs(fcn)
582+
list = HC_EmptyArgs()
540583
)
541584
}
542585

@@ -545,14 +588,15 @@ private predicate mk_ArgCons(Function fcn, HashCons hc, int i, HC_Args list, Fun
545588
* Holds if `fc` is a call to `fcn`, `fc`'s first `i` arguments have hash-cons
546589
* `list`, and `fc`'s argument at index `i` has hash-cons `hc`.
547590
*/
548-
private predicate mk_AllocArgCons(Function fcn, HashCons hc, int i, HC_Alloc list, boolean aligned, FunctionCall fc) {
549-
analyzableFunctionCall(fc) and
550-
fc.getTarget() = fcn and
551-
hc = hashCons(fc.getArgument(i).getFullyConverted()) and
591+
private predicate mk_AllocArgCons(Function fcn, HashCons hc, int i, HC_Alloc list, boolean aligned,
592+
Call c) {
593+
analyzableCall(c) and
594+
c.getTarget() = fcn and
595+
hc = hashCons(c.getArgument(i).getFullyConverted()) and
552596
(
553597
exists(HashCons head, HC_Alloc tail |
554598
list = HC_AllocArgCons(fcn, head, i - 1, tail, aligned) and
555-
mk_AllocArgCons(fcn, head, i - 1, tail, aligned, fc) and
599+
mk_AllocArgCons(fcn, head, i - 1, tail, aligned, c) and
556600
(
557601
aligned = true and
558602
i > 2
@@ -735,6 +779,34 @@ private predicate mk_SizeofExpr(HashCons child, SizeofExprOperator e) {
735779
child = hashCons(e.getAChild())
736780
}
737781

782+
private predicate analyzableUuidofOperator(UuidofOperator e) {
783+
strictcount(e.getTypeOperand()) = 1
784+
}
785+
786+
private predicate mk_UuidofOperator(Type t, UuidofOperator e) {
787+
analyzableUuidofOperator(e) and
788+
t = e.getTypeOperand()
789+
}
790+
791+
private predicate analyzableTypeidType(TypeidOperator e) {
792+
strictcount(e.getAChild()) = 0
793+
}
794+
795+
private predicate mk_TypeidType(Type t, TypeidOperator e) {
796+
analyzableTypeidType(e) and
797+
t = e.getResultType()
798+
}
799+
800+
private predicate analyzableTypeidExpr(Expr e) {
801+
e instanceof TypeidOperator and
802+
strictcount(e.getAChild().getFullyConverted()) = 1
803+
}
804+
805+
private predicate mk_TypeidExpr(HashCons child, TypeidOperator e) {
806+
analyzableTypeidExpr(e) and
807+
child = hashCons(e.getAChild())
808+
}
809+
738810
private predicate analyzableAlignofType(AlignofTypeOperator e) {
739811
strictcount(e.getType().getUnspecifiedType()) = 1 and
740812
strictcount(e.getTypeOperand()) = 1
@@ -851,6 +923,30 @@ private predicate mk_ReThrowExpr(ReThrowExpr te) {
851923
any()
852924
}
853925

926+
private predicate analyzableConditionalExpr(ConditionalExpr ce) {
927+
strictcount(ce.getCondition().getFullyConverted()) = 1 and
928+
strictcount(ce.getThen().getFullyConverted()) = 1 and
929+
strictcount(ce.getElse().getFullyConverted()) = 1
930+
}
931+
932+
private predicate mk_ConditionalExpr(HashCons cond, HashCons trueHc, HashCons falseHc,
933+
ConditionalExpr ce) {
934+
analyzableConditionalExpr(ce) and
935+
cond.getAnExpr() = ce.getCondition() and
936+
trueHc.getAnExpr() = ce.getThen() and
937+
falseHc.getAnExpr() = ce.getElse()
938+
}
939+
940+
private predicate analyzableNoExceptExpr(NoExceptExpr nee) {
941+
strictcount(nee.getAChild().getFullyConverted()) = 1
942+
}
943+
944+
private predicate mk_NoExceptExpr(HashCons child, NoExceptExpr nee) {
945+
analyzableNoExceptExpr(nee) and
946+
nee.getExpr() = child.getAnExpr().getFullyConverted()
947+
}
948+
949+
854950
/** Gets the hash-cons of expression `e`. */
855951
cached HashCons hashCons(Expr e) {
856952
exists (int val, Type t
@@ -914,6 +1010,11 @@ cached HashCons hashCons(Expr e) {
9141010
result = HC_NonmemberFunctionCall(fcn, args)
9151011
)
9161012
or
1013+
exists(HashCons hc, HC_Args args
1014+
| mk_ExprCall(hc, args, e) and
1015+
result = HC_ExprCall(hc, args)
1016+
)
1017+
or
9171018
exists(Function fcn, HashCons qual, HC_Args args
9181019
| mk_MemberFunctionCall(fcn, qual, args, e) and
9191020
result = HC_MemberFunctionCall(fcn, qual, args)
@@ -940,6 +1041,16 @@ cached HashCons hashCons(Expr e) {
9401041
)
9411042
or
9421043
exists(Type t
1044+
| mk_TypeidType(t, e) and
1045+
result = HC_TypeidType(t)
1046+
)
1047+
or
1048+
exists(HashCons child
1049+
| mk_TypeidExpr(child, e) and
1050+
result = HC_TypeidExpr(child)
1051+
)
1052+
or
1053+
exists(Type t
9431054
| mk_AlignofType(t, e) and
9441055
result = HC_AlignofType(t)
9451056
)
@@ -979,6 +1090,11 @@ cached HashCons hashCons(Expr e) {
9791090
result = HC_ReThrowExpr()
9801091
)
9811092
or
1093+
exists(HashCons cond, HashCons thenHC, HashCons elseHC
1094+
| mk_ConditionalExpr(cond, thenHC, elseHC, e) and
1095+
result = HC_ConditionalExpr(cond, thenHC, elseHC)
1096+
)
1097+
or
9821098
(
9831099
mk_Nullptr(e) and
9841100
result = HC_Nullptr()
@@ -1011,16 +1127,22 @@ predicate analyzableExpr(Expr e, string kind) {
10111127
(analyzablePointerDereferenceExpr(e) and kind = "PointerDereferenceExpr") or
10121128
(analyzableNonmemberFunctionCall(e) and kind = "NonmemberFunctionCall") or
10131129
(analyzableMemberFunctionCall(e) and kind = "MemberFunctionCall") or
1130+
(analyzableExprCall(e) and kind = "ExprCall") or
10141131
(analyzableNewExpr(e) and kind = "NewExpr") or
10151132
(analyzableNewArrayExpr(e) and kind = "NewArrayExpr") or
10161133
(analyzableSizeofType(e) and kind = "SizeofTypeOperator") or
10171134
(analyzableSizeofExpr(e) and kind = "SizeofExprOperator") or
10181135
(analyzableAlignofType(e) and kind = "AlignofTypeOperator") or
10191136
(analyzableAlignofExpr(e) and kind = "AlignofExprOperator") or
1137+
(analyzableUuidofOperator(e) and kind = "UuidofOperator") or
1138+
(analyzableTypeidType(e) and kind = "TypeidType") or
1139+
(analyzableTypeidExpr(e) and kind = "TypeidExpr") or
10201140
(analyzableClassAggregateLiteral(e) and kind = "ClassAggregateLiteral") or
10211141
(analyzableArrayAggregateLiteral(e) and kind = "ArrayAggregateLiteral") or
10221142
(analyzableDeleteExpr(e) and kind = "DeleteExpr") or
10231143
(analyzableDeleteArrayExpr(e) and kind = "DeleteArrayExpr") or
10241144
(analyzableThrowExpr(e) and kind = "ThrowExpr") or
1025-
(analyzableReThrowExpr(e) and kind = "ReThrowExpr")
1145+
(analyzableReThrowExpr(e) and kind = "ReThrowExpr") or
1146+
(analyzableConditionalExpr(e) and kind = "ConditionalExpr") or
1147+
(analyzableNoExceptExpr(e) and kind = "NoExceptExpr")
10261148
}

cpp/ql/test/library-tests/valuenumbering/HashCons/HashCons.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,13 @@
111111
| test.cpp:311:5:311:5 | 0 | 311:c5-c5 312:c5-c5 315:c5-c5 44:c9-c9 51:c25-c25 88:c12-c12 |
112112
| test.cpp:313:3:313:6 | access to array | 313:c3-c6 314:c3-c6 |
113113
| test.cpp:315:3:315:3 | y | 315:c3-c3 316:c3-c3 |
114+
| test.cpp:323:3:323:11 | test_18_p | 323:c3-c11 324:c3-c11 |
115+
| test.cpp:323:3:323:13 | call to expression | 323:c3-c13 324:c3-c13 |
116+
| test.cpp:327:3:327:11 | test_19_p | 327:c3-c11 328:c3-c11 329:c3-c11 |
117+
| test.cpp:327:3:327:17 | call to expression | 327:c3-c17 328:c3-c17 |
118+
| test.cpp:327:13:327:13 | x | 327:c13-c13 328:c13-c13 329:c16-c16 |
119+
| test.cpp:327:16:327:16 | y | 327:c16-c16 328:c16-c16 329:c13-c13 |
120+
| test.cpp:333:3:333:8 | ... == ... | 333:c3-c8 334:c3-c8 336:c3-c8 |
121+
| test.cpp:333:3:333:16 | ... ? ... : ... | 333:c3-c16 334:c3-c16 |
122+
| test.cpp:333:12:333:12 | x | 333:c12-c12 333:c3-c3 334:c12-c12 334:c3-c3 335:c12-c12 335:c8-c8 336:c16-c16 336:c3-c3 |
123+
| test.cpp:333:16:333:16 | y | 333:c16-c16 333:c8-c8 334:c16-c16 334:c8-c8 335:c16-c16 335:c3-c3 336:c12-c12 336:c8-c8 |

cpp/ql/test/library-tests/valuenumbering/HashCons/test.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,23 @@ void test19(int *x, int *y) {
315315
y[0];
316316
y[1];
317317
}
318+
319+
void test20(int *x, int *y) {
320+
void (*test_18_p)() = &test18;
321+
void (*test_17_p)() = &test17;
322+
void (*test_19_p)(int *, int *) = &test19;
323+
test_18_p();
324+
test_18_p();
325+
test_17_p();
326+
327+
test_19_p(x, y);
328+
test_19_p(x, y);
329+
test_19_p(y, x);
330+
}
331+
332+
void test21(int x, int y) {
333+
x == y ? x : y;
334+
x == y ? x : y;
335+
y == x ? x : y;
336+
x == y ? y : x;
337+
}

0 commit comments

Comments
 (0)