Skip to content

Commit 7b7ff1f

Browse files
authored
Merge pull request github#3089 from geoffw0/sideeffect
CPP: Add side effect models for strcpy and strcat.
2 parents 0feb7f8 + 6d6ad4a commit 7b7ff1f

File tree

5 files changed

+171
-2
lines changed

5 files changed

+171
-2
lines changed

cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import semmle.code.cpp.models.interfaces.ArrayFunction
22
import semmle.code.cpp.models.interfaces.DataFlow
33
import semmle.code.cpp.models.interfaces.Taint
4+
import semmle.code.cpp.models.interfaces.SideEffect
45

56
/**
67
* The standard function `strcat` and its wide, sized, and Microsoft variants.
78
*/
8-
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction {
9+
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
910
StrcatFunction() {
1011
exists(string name | name = getName() |
1112
name = "strcat" or // strcat(dst, src)
@@ -56,4 +57,19 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction {
5657
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
5758

5859
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
60+
61+
override predicate hasOnlySpecificReadSideEffects() { any() }
62+
63+
override predicate hasOnlySpecificWriteSideEffects() { any() }
64+
65+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
66+
i = 0 and
67+
buffer = true and
68+
mustWrite = false
69+
}
70+
71+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
72+
(i = 0 or i = 1) and
73+
buffer = true
74+
}
5975
}

cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import semmle.code.cpp.models.interfaces.ArrayFunction
22
import semmle.code.cpp.models.interfaces.DataFlow
33
import semmle.code.cpp.models.interfaces.Taint
4+
import semmle.code.cpp.models.interfaces.SideEffect
45

56
/**
67
* The standard function `strcpy` and its wide, sized, and Microsoft variants.
78
*/
8-
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
9+
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction {
910
StrcpyFunction() {
1011
this.hasName("strcpy") or
1112
this.hasName("_mbscpy") or
@@ -74,4 +75,23 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
7475
output.isReturnValueDeref()
7576
)
7677
}
78+
79+
override predicate hasOnlySpecificReadSideEffects() { any() }
80+
81+
override predicate hasOnlySpecificWriteSideEffects() { any() }
82+
83+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
84+
i = 0 and
85+
buffer = true and
86+
mustWrite = false
87+
}
88+
89+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
90+
i = 1 and
91+
buffer = true
92+
}
93+
94+
override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
95+
hasArrayWithVariableSize(i, result)
96+
}
7797
}

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8475,6 +8475,76 @@ ir.cpp:
84758475
# 1243| Type = [PointerType] const char *
84768476
# 1243| ValueCategory = prvalue(load)
84778477
# 1244| 3: [ReturnStmt] return ...
8478+
# 1248| [TopLevelFunction] char* strcpy(char*, char const*)
8479+
# 1248| params:
8480+
# 1248| 0: [Parameter] destination
8481+
# 1248| Type = [CharPointerType] char *
8482+
# 1248| 1: [Parameter] source
8483+
# 1248| Type = [PointerType] const char *
8484+
# 1249| [TopLevelFunction] char* strcat(char*, char const*)
8485+
# 1249| params:
8486+
# 1249| 0: [Parameter] destination
8487+
# 1249| Type = [CharPointerType] char *
8488+
# 1249| 1: [Parameter] source
8489+
# 1249| Type = [PointerType] const char *
8490+
# 1251| [TopLevelFunction] void test_strings(char*, char*)
8491+
# 1251| params:
8492+
# 1251| 0: [Parameter] s1
8493+
# 1251| Type = [CharPointerType] char *
8494+
# 1251| 1: [Parameter] s2
8495+
# 1251| Type = [CharPointerType] char *
8496+
# 1251| body: [Block] { ... }
8497+
# 1252| 0: [DeclStmt] declaration
8498+
# 1252| 0: [VariableDeclarationEntry] definition of buffer
8499+
# 1252| Type = [ArrayType] char[1024]
8500+
# 1252| init: [Initializer] initializer for buffer
8501+
# 1252| expr: [ArrayAggregateLiteral] {...}
8502+
# 1252| Type = [ArrayType] char[1024]
8503+
# 1252| ValueCategory = prvalue
8504+
# 1252| [0]: [CStyleCast] (char)...
8505+
# 1252| Conversion = [IntegralConversion] integral conversion
8506+
# 1252| Type = [PlainCharType] char
8507+
# 1252| Value = [CStyleCast] 0
8508+
# 1252| ValueCategory = prvalue
8509+
# 1252| expr: [Literal] 0
8510+
# 1252| Type = [IntType] int
8511+
# 1252| Value = [Literal] 0
8512+
# 1252| ValueCategory = prvalue
8513+
# 1254| 1: [ExprStmt] ExprStmt
8514+
# 1254| 0: [FunctionCall] call to strcpy
8515+
# 1254| Type = [CharPointerType] char *
8516+
# 1254| ValueCategory = prvalue
8517+
# 1254| 0: [ArrayToPointerConversion] array to pointer conversion
8518+
# 1254| Type = [CharPointerType] char *
8519+
# 1254| ValueCategory = prvalue
8520+
# 1254| expr: [VariableAccess] buffer
8521+
# 1254| Type = [ArrayType] char[1024]
8522+
# 1254| ValueCategory = lvalue
8523+
# 1254| 1: [CStyleCast] (const char *)...
8524+
# 1254| Conversion = [PointerConversion] pointer conversion
8525+
# 1254| Type = [PointerType] const char *
8526+
# 1254| ValueCategory = prvalue
8527+
# 1254| expr: [VariableAccess] s1
8528+
# 1254| Type = [CharPointerType] char *
8529+
# 1254| ValueCategory = prvalue(load)
8530+
# 1255| 2: [ExprStmt] ExprStmt
8531+
# 1255| 0: [FunctionCall] call to strcat
8532+
# 1255| Type = [CharPointerType] char *
8533+
# 1255| ValueCategory = prvalue
8534+
# 1255| 0: [ArrayToPointerConversion] array to pointer conversion
8535+
# 1255| Type = [CharPointerType] char *
8536+
# 1255| ValueCategory = prvalue
8537+
# 1255| expr: [VariableAccess] buffer
8538+
# 1255| Type = [ArrayType] char[1024]
8539+
# 1255| ValueCategory = lvalue
8540+
# 1255| 1: [CStyleCast] (const char *)...
8541+
# 1255| Conversion = [PointerConversion] pointer conversion
8542+
# 1255| Type = [PointerType] const char *
8543+
# 1255| ValueCategory = prvalue
8544+
# 1255| expr: [VariableAccess] s2
8545+
# 1255| Type = [CharPointerType] char *
8546+
# 1255| ValueCategory = prvalue(load)
8547+
# 1256| 3: [ReturnStmt] return ...
84788548
perf-regression.cpp:
84798549
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
84808550
# 4| params:

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,4 +1243,16 @@ void staticLocalWithConstructor(const char* dynamic) {
12431243
static String c(dynamic);
12441244
}
12451245

1246+
// --- strings ---
1247+
1248+
char *strcpy(char *destination, const char *source);
1249+
char *strcat(char *destination, const char *source);
1250+
1251+
void test_strings(char *s1, char *s2) {
1252+
char buffer[1024] = {0};
1253+
1254+
strcpy(buffer, s1);
1255+
strcat(buffer, s2);
1256+
}
1257+
12461258
// semmle-extractor-options: -std=c++17 --clang

cpp/ql/test/library-tests/ir/ir/raw_ir.expected

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6417,6 +6417,57 @@ ir.cpp:
64176417
# 1241| mu1241_6(bool) = Store : &:r1241_1, r1241_5
64186418
#-----| Goto -> Block 1
64196419

6420+
# 1251| void test_strings(char*, char*)
6421+
# 1251| Block 0
6422+
# 1251| v1251_1(void) = EnterFunction :
6423+
# 1251| mu1251_2(unknown) = AliasedDefinition :
6424+
# 1251| mu1251_3(unknown) = InitializeNonLocal :
6425+
# 1251| mu1251_4(unknown) = UnmodeledDefinition :
6426+
# 1251| r1251_5(glval<char *>) = VariableAddress[s1] :
6427+
# 1251| mu1251_6(char *) = InitializeParameter[s1] : &:r1251_5
6428+
# 1251| r1251_7(char *) = Load : &:r1251_5, ~mu1251_6
6429+
# 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7
6430+
# 1251| r1251_9(glval<char *>) = VariableAddress[s2] :
6431+
# 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9
6432+
# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_10
6433+
# 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11
6434+
# 1252| r1252_1(glval<char[1024]>) = VariableAddress[buffer] :
6435+
# 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1
6436+
# 1252| r1252_3(int) = Constant[0] :
6437+
# 1252| r1252_4(glval<char>) = PointerAdd[1] : r1252_1, r1252_3
6438+
# 1252| r1252_5(char) = Constant[0] :
6439+
# 1252| mu1252_6(char) = Store : &:r1252_4, r1252_5
6440+
# 1252| r1252_7(int) = Constant[1] :
6441+
# 1252| r1252_8(glval<char>) = PointerAdd[1] : r1252_1, r1252_7
6442+
# 1252| r1252_9(unknown[1023]) = Constant[0] :
6443+
# 1252| mu1252_10(unknown[1023]) = Store : &:r1252_8, r1252_9
6444+
# 1254| r1254_1(glval<unknown>) = FunctionAddress[strcpy] :
6445+
# 1254| r1254_2(glval<char[1024]>) = VariableAddress[buffer] :
6446+
# 1254| r1254_3(char *) = Convert : r1254_2
6447+
# 1254| r1254_4(glval<char *>) = VariableAddress[s1] :
6448+
# 1254| r1254_5(char *) = Load : &:r1254_4, ~mu1251_4
6449+
# 1254| r1254_6(char *) = Convert : r1254_5
6450+
# 1254| r1254_7(char *) = Call : func:r1254_1, 0:r1254_3, 1:r1254_6
6451+
# 1254| v1254_8(void) = ^BufferReadSideEffect[1] : &:r1254_6, ~mu1251_4
6452+
# 1254| mu1254_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1254_3
6453+
# 1255| r1255_1(glval<unknown>) = FunctionAddress[strcat] :
6454+
# 1255| r1255_2(glval<char[1024]>) = VariableAddress[buffer] :
6455+
# 1255| r1255_3(char *) = Convert : r1255_2
6456+
# 1255| r1255_4(glval<char *>) = VariableAddress[s2] :
6457+
# 1255| r1255_5(char *) = Load : &:r1255_4, ~mu1251_4
6458+
# 1255| r1255_6(char *) = Convert : r1255_5
6459+
# 1255| r1255_7(char *) = Call : func:r1255_1, 0:r1255_3, 1:r1255_6
6460+
# 1255| v1255_8(void) = ^BufferReadSideEffect[0] : &:r1255_3, ~mu1251_4
6461+
# 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~mu1251_4
6462+
# 1255| mu1255_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1255_3
6463+
# 1256| v1256_1(void) = NoOp :
6464+
# 1251| v1251_13(void) = ReturnIndirection : &:r1251_7, ~mu1251_4
6465+
# 1251| v1251_14(void) = ReturnIndirection : &:r1251_11, ~mu1251_4
6466+
# 1251| v1251_15(void) = ReturnVoid :
6467+
# 1251| v1251_16(void) = UnmodeledUse : mu*
6468+
# 1251| v1251_17(void) = AliasedUse : ~mu1251_4
6469+
# 1251| v1251_18(void) = ExitFunction :
6470+
64206471
perf-regression.cpp:
64216472
# 6| void Big::Big()
64226473
# 6| Block 0

0 commit comments

Comments
 (0)