Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.SideEffect

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

override predicate hasArrayWithUnknownSize(int param) { param = 0 }

override predicate hasOnlySpecificReadSideEffects() { any() }

override predicate hasOnlySpecificWriteSideEffects() { any() }

override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and
buffer = true and
mustWrite = false
}

override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
(i = 0 or i = 1) and
buffer = true
}
}
22 changes: 21 additions & 1 deletion cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.SideEffect

/**
* The standard function `strcpy` and its wide, sized, and Microsoft variants.
*/
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction {
StrcpyFunction() {
this.hasName("strcpy") or
this.hasName("_mbscpy") or
Expand Down Expand Up @@ -74,4 +75,23 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
output.isReturnValueDeref()
)
}

override predicate hasOnlySpecificReadSideEffects() { any() }

override predicate hasOnlySpecificWriteSideEffects() { any() }

override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and
buffer = true and
mustWrite = false
}

override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 1 and
buffer = true
}

override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
hasArrayWithVariableSize(i, result)
}
}
70 changes: 70 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/PrintAST.expected
Original file line number Diff line number Diff line change
Expand Up @@ -8475,6 +8475,76 @@ ir.cpp:
# 1243| Type = [PointerType] const char *
# 1243| ValueCategory = prvalue(load)
# 1244| 3: [ReturnStmt] return ...
# 1248| [TopLevelFunction] char* strcpy(char*, char const*)
# 1248| params:
# 1248| 0: [Parameter] destination
# 1248| Type = [CharPointerType] char *
# 1248| 1: [Parameter] source
# 1248| Type = [PointerType] const char *
# 1249| [TopLevelFunction] char* strcat(char*, char const*)
# 1249| params:
# 1249| 0: [Parameter] destination
# 1249| Type = [CharPointerType] char *
# 1249| 1: [Parameter] source
# 1249| Type = [PointerType] const char *
# 1251| [TopLevelFunction] void test_strings(char*, char*)
# 1251| params:
# 1251| 0: [Parameter] s1
# 1251| Type = [CharPointerType] char *
# 1251| 1: [Parameter] s2
# 1251| Type = [CharPointerType] char *
# 1251| body: [Block] { ... }
# 1252| 0: [DeclStmt] declaration
# 1252| 0: [VariableDeclarationEntry] definition of buffer
# 1252| Type = [ArrayType] char[1024]
# 1252| init: [Initializer] initializer for buffer
# 1252| expr: [ArrayAggregateLiteral] {...}
# 1252| Type = [ArrayType] char[1024]
# 1252| ValueCategory = prvalue
# 1252| [0]: [CStyleCast] (char)...
# 1252| Conversion = [IntegralConversion] integral conversion
# 1252| Type = [PlainCharType] char
# 1252| Value = [CStyleCast] 0
# 1252| ValueCategory = prvalue
# 1252| expr: [Literal] 0
# 1252| Type = [IntType] int
# 1252| Value = [Literal] 0
# 1252| ValueCategory = prvalue
# 1254| 1: [ExprStmt] ExprStmt
# 1254| 0: [FunctionCall] call to strcpy
# 1254| Type = [CharPointerType] char *
# 1254| ValueCategory = prvalue
# 1254| 0: [ArrayToPointerConversion] array to pointer conversion
# 1254| Type = [CharPointerType] char *
# 1254| ValueCategory = prvalue
# 1254| expr: [VariableAccess] buffer
# 1254| Type = [ArrayType] char[1024]
# 1254| ValueCategory = lvalue
# 1254| 1: [CStyleCast] (const char *)...
# 1254| Conversion = [PointerConversion] pointer conversion
# 1254| Type = [PointerType] const char *
# 1254| ValueCategory = prvalue
# 1254| expr: [VariableAccess] s1
# 1254| Type = [CharPointerType] char *
# 1254| ValueCategory = prvalue(load)
# 1255| 2: [ExprStmt] ExprStmt
# 1255| 0: [FunctionCall] call to strcat
# 1255| Type = [CharPointerType] char *
# 1255| ValueCategory = prvalue
# 1255| 0: [ArrayToPointerConversion] array to pointer conversion
# 1255| Type = [CharPointerType] char *
# 1255| ValueCategory = prvalue
# 1255| expr: [VariableAccess] buffer
# 1255| Type = [ArrayType] char[1024]
# 1255| ValueCategory = lvalue
# 1255| 1: [CStyleCast] (const char *)...
# 1255| Conversion = [PointerConversion] pointer conversion
# 1255| Type = [PointerType] const char *
# 1255| ValueCategory = prvalue
# 1255| expr: [VariableAccess] s2
# 1255| Type = [CharPointerType] char *
# 1255| ValueCategory = prvalue(load)
# 1256| 3: [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| params:
Expand Down
12 changes: 12 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1243,4 +1243,16 @@ void staticLocalWithConstructor(const char* dynamic) {
static String c(dynamic);
}

// --- strings ---

char *strcpy(char *destination, const char *source);
char *strcat(char *destination, const char *source);

void test_strings(char *s1, char *s2) {
char buffer[1024] = {0};

strcpy(buffer, s1);
strcat(buffer, s2);
}

// semmle-extractor-options: -std=c++17 --clang
51 changes: 51 additions & 0 deletions cpp/ql/test/library-tests/ir/ir/raw_ir.expected
Original file line number Diff line number Diff line change
Expand Up @@ -6417,6 +6417,57 @@ ir.cpp:
# 1241| mu1241_6(bool) = Store : &:r1241_1, r1241_5
#-----| Goto -> Block 1

# 1251| void test_strings(char*, char*)
# 1251| Block 0
# 1251| v1251_1(void) = EnterFunction :
# 1251| mu1251_2(unknown) = AliasedDefinition :
# 1251| mu1251_3(unknown) = InitializeNonLocal :
# 1251| mu1251_4(unknown) = UnmodeledDefinition :
# 1251| r1251_5(glval<char *>) = VariableAddress[s1] :
# 1251| mu1251_6(char *) = InitializeParameter[s1] : &:r1251_5
# 1251| r1251_7(char *) = Load : &:r1251_5, ~mu1251_6
# 1251| mu1251_8(unknown) = InitializeIndirection[s1] : &:r1251_7
# 1251| r1251_9(glval<char *>) = VariableAddress[s2] :
# 1251| mu1251_10(char *) = InitializeParameter[s2] : &:r1251_9
# 1251| r1251_11(char *) = Load : &:r1251_9, ~mu1251_10
# 1251| mu1251_12(unknown) = InitializeIndirection[s2] : &:r1251_11
# 1252| r1252_1(glval<char[1024]>) = VariableAddress[buffer] :
# 1252| mu1252_2(char[1024]) = Uninitialized[buffer] : &:r1252_1
# 1252| r1252_3(int) = Constant[0] :
# 1252| r1252_4(glval<char>) = PointerAdd[1] : r1252_1, r1252_3
# 1252| r1252_5(char) = Constant[0] :
# 1252| mu1252_6(char) = Store : &:r1252_4, r1252_5
# 1252| r1252_7(int) = Constant[1] :
# 1252| r1252_8(glval<char>) = PointerAdd[1] : r1252_1, r1252_7
# 1252| r1252_9(unknown[1023]) = Constant[0] :
# 1252| mu1252_10(unknown[1023]) = Store : &:r1252_8, r1252_9
# 1254| r1254_1(glval<unknown>) = FunctionAddress[strcpy] :
# 1254| r1254_2(glval<char[1024]>) = VariableAddress[buffer] :
# 1254| r1254_3(char *) = Convert : r1254_2
# 1254| r1254_4(glval<char *>) = VariableAddress[s1] :
# 1254| r1254_5(char *) = Load : &:r1254_4, ~mu1251_4
# 1254| r1254_6(char *) = Convert : r1254_5
# 1254| r1254_7(char *) = Call : func:r1254_1, 0:r1254_3, 1:r1254_6
# 1254| v1254_8(void) = ^BufferReadSideEffect[1] : &:r1254_6, ~mu1251_4
# 1254| mu1254_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1254_3
# 1255| r1255_1(glval<unknown>) = FunctionAddress[strcat] :
# 1255| r1255_2(glval<char[1024]>) = VariableAddress[buffer] :
# 1255| r1255_3(char *) = Convert : r1255_2
# 1255| r1255_4(glval<char *>) = VariableAddress[s2] :
# 1255| r1255_5(char *) = Load : &:r1255_4, ~mu1251_4
# 1255| r1255_6(char *) = Convert : r1255_5
# 1255| r1255_7(char *) = Call : func:r1255_1, 0:r1255_3, 1:r1255_6
# 1255| v1255_8(void) = ^BufferReadSideEffect[0] : &:r1255_3, ~mu1251_4
# 1255| v1255_9(void) = ^BufferReadSideEffect[1] : &:r1255_6, ~mu1251_4
# 1255| mu1255_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r1255_3
# 1256| v1256_1(void) = NoOp :
# 1251| v1251_13(void) = ReturnIndirection : &:r1251_7, ~mu1251_4
# 1251| v1251_14(void) = ReturnIndirection : &:r1251_11, ~mu1251_4
# 1251| v1251_15(void) = ReturnVoid :
# 1251| v1251_16(void) = UnmodeledUse : mu*
# 1251| v1251_17(void) = AliasedUse : ~mu1251_4
# 1251| v1251_18(void) = ExitFunction :

perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0
Expand Down