Skip to content

Commit 23001d5

Browse files
authored
Merge pull request #1566 from rdmarsh2/rdmarsh/cpp/pure-functions-effect-model
C++: alias and side effect info for pure functions
2 parents db6be05 + c195420 commit 23001d5

File tree

4 files changed

+175
-16
lines changed

4 files changed

+175
-16
lines changed
Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
import semmle.code.cpp.models.interfaces.ArrayFunction
22
import semmle.code.cpp.models.interfaces.Taint
3+
import semmle.code.cpp.models.interfaces.Alias
4+
import semmle.code.cpp.models.interfaces.SideEffect
35

4-
class PureFunction extends ArrayFunction, TaintFunction {
5-
PureFunction() {
6+
class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction {
7+
PureStrFunction() {
68
exists(string name |
7-
hasName(name) and
9+
hasGlobalName(name) and
810
(
9-
name = "abs"
10-
or name = "atof"
11+
name = "atof"
1112
or name = "atoi"
1213
or name = "atol"
1314
or name = "atoll"
14-
or name = "labs"
1515
or name = "strcasestr"
1616
or name = "strchnul"
1717
or name = "strchr"
1818
or name = "strchrnul"
19+
or name = "strstr"
20+
or name = "strpbrk"
1921
or name = "strcmp"
2022
or name = "strcspn"
2123
or name = "strlen"
2224
or name = "strncmp"
2325
or name = "strnlen"
2426
or name = "strrchr"
2527
or name = "strspn"
26-
or name = "strstr"
2728
or name = "strtod"
2829
or name = "strtof"
2930
or name = "strtol"
@@ -40,18 +41,67 @@ class PureFunction extends ArrayFunction, TaintFunction {
4041

4142
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
4243
exists (ParameterIndex i |
43-
input.isInParameter(i) or
44-
(
45-
input.isInParameterPointer(i) and
46-
getParameter(i).getUnspecifiedType() instanceof PointerType
47-
)
44+
input.isInParameter(i) and
45+
exists(getParameter(i))
46+
or
47+
input.isInParameterPointer(i) and
48+
getParameter(i).getUnspecifiedType() instanceof PointerType
4849
) and
4950
(
50-
(
51-
output.isOutReturnPointer() and
52-
getUnspecifiedType() instanceof PointerType
53-
) or
51+
output.isOutReturnPointer() and
52+
getUnspecifiedType() instanceof PointerType
53+
or
5454
output.isOutReturnValue()
5555
)
5656
}
57+
58+
override predicate parameterNeverEscapes(int i) {
59+
getParameter(i).getUnspecifiedType() instanceof PointerType and
60+
not parameterEscapesOnlyViaReturn(i)
61+
}
62+
63+
override predicate parameterEscapesOnlyViaReturn(int i) {
64+
i = 0 and
65+
getUnspecifiedType() instanceof PointerType
66+
}
67+
68+
override predicate parameterIsAlwaysReturned(int i) {
69+
none()
70+
}
71+
72+
override predicate neverReadsMemory() {
73+
none()
74+
}
75+
76+
override predicate neverWritesMemory() {
77+
any()
78+
}
79+
}
80+
81+
class PureFunction extends TaintFunction, SideEffectFunction {
82+
PureFunction() {
83+
exists(string name |
84+
hasGlobalName(name) and
85+
(
86+
name = "abs" or
87+
name = "labs"
88+
)
89+
)
90+
}
91+
92+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
93+
exists (ParameterIndex i |
94+
input.isInParameter(i) and
95+
exists(getParameter(i))
96+
) and
97+
output.isOutReturnValue()
98+
}
99+
100+
override predicate neverReadsMemory() {
101+
any()
102+
}
103+
104+
override predicate neverWritesMemory() {
105+
any()
106+
}
57107
}

cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,3 +758,52 @@ ssa.cpp:
758758
# 184| v0_22(void) = ReturnVoid :
759759
# 184| v0_23(void) = UnmodeledUse : mu*
760760
# 184| v0_24(void) = ExitFunction :
761+
762+
# 198| int PureFunctions(char*, char*, int)
763+
# 198| Block 0
764+
# 198| v0_0(void) = EnterFunction :
765+
# 198| m0_1(unknown) = AliasedDefinition :
766+
# 198| mu0_2(unknown) = UnmodeledDefinition :
767+
# 198| r0_3(glval<char *>) = VariableAddress[str1] :
768+
# 198| m0_4(char *) = InitializeParameter[str1] : &:r0_3
769+
# 198| r0_5(glval<char *>) = VariableAddress[str2] :
770+
# 198| m0_6(char *) = InitializeParameter[str2] : &:r0_5
771+
# 198| r0_7(glval<int>) = VariableAddress[x] :
772+
# 198| m0_8(int) = InitializeParameter[x] : &:r0_7
773+
# 199| r0_9(glval<int>) = VariableAddress[ret] :
774+
# 199| r0_10(glval<unknown>) = FunctionAddress[strcmp] :
775+
# 199| r0_11(glval<char *>) = VariableAddress[str1] :
776+
# 199| r0_12(char *) = Load : &:r0_11, m0_4
777+
# 199| r0_13(char *) = Convert : r0_12
778+
# 199| r0_14(glval<char *>) = VariableAddress[str2] :
779+
# 199| r0_15(char *) = Load : &:r0_14, m0_6
780+
# 199| r0_16(char *) = Convert : r0_15
781+
# 199| r0_17(int) = Call : func:r0_10, 0:r0_13, 1:r0_16
782+
# 199| v0_18(void) = ^CallReadSideEffect : ~m0_1
783+
# 199| m0_19(int) = Store : &:r0_9, r0_17
784+
# 200| r0_20(glval<unknown>) = FunctionAddress[strlen] :
785+
# 200| r0_21(glval<char *>) = VariableAddress[str1] :
786+
# 200| r0_22(char *) = Load : &:r0_21, m0_4
787+
# 200| r0_23(char *) = Convert : r0_22
788+
# 200| r0_24(int) = Call : func:r0_20, 0:r0_23
789+
# 200| v0_25(void) = ^CallReadSideEffect : ~m0_1
790+
# 200| r0_26(glval<int>) = VariableAddress[ret] :
791+
# 200| r0_27(int) = Load : &:r0_26, m0_19
792+
# 200| r0_28(int) = Add : r0_27, r0_24
793+
# 200| m0_29(int) = Store : &:r0_26, r0_28
794+
# 201| r0_30(glval<unknown>) = FunctionAddress[abs] :
795+
# 201| r0_31(glval<int>) = VariableAddress[x] :
796+
# 201| r0_32(int) = Load : &:r0_31, m0_8
797+
# 201| r0_33(int) = Call : func:r0_30, 0:r0_32
798+
# 201| r0_34(glval<int>) = VariableAddress[ret] :
799+
# 201| r0_35(int) = Load : &:r0_34, m0_29
800+
# 201| r0_36(int) = Add : r0_35, r0_33
801+
# 201| m0_37(int) = Store : &:r0_34, r0_36
802+
# 202| r0_38(glval<int>) = VariableAddress[#return] :
803+
# 202| r0_39(glval<int>) = VariableAddress[ret] :
804+
# 202| r0_40(int) = Load : &:r0_39, m0_37
805+
# 202| m0_41(int) = Store : &:r0_38, r0_40
806+
# 198| r0_42(glval<int>) = VariableAddress[#return] :
807+
# 198| v0_43(void) = ReturnValue : &:r0_42, m0_41
808+
# 198| v0_44(void) = UnmodeledUse : mu*
809+
# 198| v0_45(void) = ExitFunction :

cpp/ql/test/library-tests/ir/ssa/ssa.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,4 +189,15 @@ static void AsmStmtWithOutputs(unsigned int& a, unsigned int& b, unsigned int& c
189189
: "+a" (a), "+b" (b)
190190
: "c" (c), "d" (d)
191191
);
192+
}
193+
194+
int strcmp(const char *, const char *);
195+
int strlen(const char *);
196+
int abs(int);
197+
198+
int PureFunctions(char *str1, char *str2, int x) {
199+
int ret = strcmp(str1, str2);
200+
ret += strlen(str1);
201+
ret += abs(x);
202+
return ret;
192203
}

cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,3 +724,52 @@ ssa.cpp:
724724
# 184| v0_17(void) = ReturnVoid :
725725
# 184| v0_18(void) = UnmodeledUse : mu*
726726
# 184| v0_19(void) = ExitFunction :
727+
728+
# 198| int PureFunctions(char*, char*, int)
729+
# 198| Block 0
730+
# 198| v0_0(void) = EnterFunction :
731+
# 198| mu0_1(unknown) = AliasedDefinition :
732+
# 198| mu0_2(unknown) = UnmodeledDefinition :
733+
# 198| r0_3(glval<char *>) = VariableAddress[str1] :
734+
# 198| m0_4(char *) = InitializeParameter[str1] : &:r0_3
735+
# 198| r0_5(glval<char *>) = VariableAddress[str2] :
736+
# 198| m0_6(char *) = InitializeParameter[str2] : &:r0_5
737+
# 198| r0_7(glval<int>) = VariableAddress[x] :
738+
# 198| m0_8(int) = InitializeParameter[x] : &:r0_7
739+
# 199| r0_9(glval<int>) = VariableAddress[ret] :
740+
# 199| r0_10(glval<unknown>) = FunctionAddress[strcmp] :
741+
# 199| r0_11(glval<char *>) = VariableAddress[str1] :
742+
# 199| r0_12(char *) = Load : &:r0_11, m0_4
743+
# 199| r0_13(char *) = Convert : r0_12
744+
# 199| r0_14(glval<char *>) = VariableAddress[str2] :
745+
# 199| r0_15(char *) = Load : &:r0_14, m0_6
746+
# 199| r0_16(char *) = Convert : r0_15
747+
# 199| r0_17(int) = Call : func:r0_10, 0:r0_13, 1:r0_16
748+
# 199| v0_18(void) = ^CallReadSideEffect : ~mu0_2
749+
# 199| m0_19(int) = Store : &:r0_9, r0_17
750+
# 200| r0_20(glval<unknown>) = FunctionAddress[strlen] :
751+
# 200| r0_21(glval<char *>) = VariableAddress[str1] :
752+
# 200| r0_22(char *) = Load : &:r0_21, m0_4
753+
# 200| r0_23(char *) = Convert : r0_22
754+
# 200| r0_24(int) = Call : func:r0_20, 0:r0_23
755+
# 200| v0_25(void) = ^CallReadSideEffect : ~mu0_2
756+
# 200| r0_26(glval<int>) = VariableAddress[ret] :
757+
# 200| r0_27(int) = Load : &:r0_26, m0_19
758+
# 200| r0_28(int) = Add : r0_27, r0_24
759+
# 200| m0_29(int) = Store : &:r0_26, r0_28
760+
# 201| r0_30(glval<unknown>) = FunctionAddress[abs] :
761+
# 201| r0_31(glval<int>) = VariableAddress[x] :
762+
# 201| r0_32(int) = Load : &:r0_31, m0_8
763+
# 201| r0_33(int) = Call : func:r0_30, 0:r0_32
764+
# 201| r0_34(glval<int>) = VariableAddress[ret] :
765+
# 201| r0_35(int) = Load : &:r0_34, m0_29
766+
# 201| r0_36(int) = Add : r0_35, r0_33
767+
# 201| m0_37(int) = Store : &:r0_34, r0_36
768+
# 202| r0_38(glval<int>) = VariableAddress[#return] :
769+
# 202| r0_39(glval<int>) = VariableAddress[ret] :
770+
# 202| r0_40(int) = Load : &:r0_39, m0_37
771+
# 202| m0_41(int) = Store : &:r0_38, r0_40
772+
# 198| r0_42(glval<int>) = VariableAddress[#return] :
773+
# 198| v0_43(void) = ReturnValue : &:r0_42, m0_41
774+
# 198| v0_44(void) = UnmodeledUse : mu*
775+
# 198| v0_45(void) = ExitFunction :

0 commit comments

Comments
 (0)