Skip to content

Commit d913654

Browse files
committed
Merge remote-tracking branch 'upstream/master' into FalsySanitizer
2 parents 0f511c9 + 78380f5 commit d913654

File tree

27 files changed

+3986
-58
lines changed

27 files changed

+3986
-58
lines changed

change-notes/1.24/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
1919
| Memory is never freed (`cpp/memory-never-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
2020
| Memory may not be freed (`cpp/memory-may-not-be-freed`) | More true positive results | This query now identifies a wider variety of buffer allocations using the `semmle.code.cpp.models.interfaces.Allocation` library. |
2121
| Missing return statement (`cpp/missing-return`) | Fewer false positive results | Functions containing `asm` statements are no longer highlighted by this query. |
22+
| No space for zero terminator (`cpp/no-space-for-terminator`) | More correct results | String arguments to formatting functions are now (usually) expected to be null terminated strings. |
2223
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | | This query is no longer run on LGTM. |
2324
| No space for zero terminator (`cpp/no-space-for-terminator`) | Fewer false positive results | This query has been modified to be more conservative when identifying which pointers point to null-terminated strings. This approach produces fewer, more accurate results. |
2425
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query no longer reports incorrect results in template classes. |

change-notes/1.24/analysis-csharp.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ The following changes in version 1.24 affect C# analysis in all applications.
2727
## Changes to code extraction
2828

2929
* Tuple expressions, for example `(int,bool)` in `default((int,bool))` are now extracted correctly.
30-
* Expression nullability flow state is extracted.
30+
* Expression nullability flow state is extracted.
31+
* Implicitly typed `stackalloc` expressions are now extracted correctly.
32+
* The difference between `stackalloc` array creations and normal array creations is extracted.
3133

3234
## Changes to libraries
3335

@@ -38,5 +40,6 @@ The following changes in version 1.24 affect C# analysis in all applications.
3840
* The taint tracking library now tracks flow through (implicit or explicit) conversion operator calls.
3941
* [Code contracts](https://docs.microsoft.com/en-us/dotnet/framework/debug-trace-profile/code-contracts) are now recognized, and are treated like any other assertion methods.
4042
* Expression nullability flow state is given by the predicates `Expr.hasNotNullFlowState()` and `Expr.hasMaybeNullFlowState()`.
43+
* `stackalloc` array creations are now represented by the QL class `Stackalloc`. Previously they were represented by the class `ArrayCreation`.
4144

4245
## Changes to autobuilder

cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,25 @@ import semmle.code.cpp.models.interfaces.Allocation
2222
predicate terminationProblem(AllocationExpr malloc, string msg) {
2323
// malloc(strlen(...))
2424
exists(StrlenCall strlen | DataFlow::localExprFlow(strlen, malloc.getSizeExpr())) and
25-
// flows into a null-terminated string function
25+
// flows to a call that implies this is a null-terminated string
2626
exists(ArrayFunction af, FunctionCall fc, int arg |
2727
DataFlow::localExprFlow(malloc, fc.getArgument(arg)) and
2828
fc.getTarget() = af and
2929
(
30-
// null terminated string
30+
// flows into null terminated string argument
3131
af.hasArrayWithNullTerminator(arg)
3232
or
33-
// likely a null terminated string (such as `strcpy`, `strcat`)
33+
// flows into likely null terminated string argument (such as `strcpy`, `strcat`)
3434
af.hasArrayWithUnknownSize(arg)
35+
or
36+
// flows into string argument to a formatting function (such as `printf`)
37+
exists(int n, FormatLiteral fl |
38+
fc.getArgument(arg) = fc.(FormattingFunctionCall).getConversionArgument(n) and
39+
fl = fc.(FormattingFunctionCall).getFormat() and
40+
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
41+
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
42+
not fl.hasPrecision(n) // exclude: `%.*s`
43+
)
3544
)
3645
) and
3746
msg = "This allocation does not include space to null-terminate the string."

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,10 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
365365
modelOut.isReturnValueDeref() and
366366
iTo = call
367367
or
368-
exists(WriteSideEffectInstruction outNode |
369-
modelOut.isParameterDeref(outNode.getIndex()) and
368+
exists(int index, WriteSideEffectInstruction outNode |
369+
modelOut.isParameterDeref(index) and
370370
iTo = outNode and
371-
outNode.getPrimaryInstruction() = call
371+
outNode = getSideEffectFor(call, index)
372372
)
373373
// TODO: add write side effects for qualifiers
374374
) and
@@ -380,8 +380,7 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
380380
or
381381
exists(int index, ReadSideEffectInstruction read |
382382
modelIn.isParameterDeref(index) and
383-
read.getIndex() = index and
384-
read.getPrimaryInstruction() = call and
383+
read = getSideEffectFor(call, index) and
385384
iFrom = read.getSideEffectOperand().getAnyDef()
386385
)
387386
or
@@ -392,6 +391,18 @@ private predicate modelFlow(Instruction iFrom, Instruction iTo) {
392391
)
393392
}
394393

394+
/**
395+
* Holds if the result is a side effect for instruction `call` on argument
396+
* index `argument`. This helper predicate makes it easy to join on both of
397+
* these columns at once, avoiding pathological join orders in case the
398+
* argument index should get joined first.
399+
*/
400+
pragma[noinline]
401+
SideEffectInstruction getSideEffectFor(CallInstruction call, int argument) {
402+
call = result.getPrimaryInstruction() and
403+
argument = result.(IndexedInstruction).getIndex()
404+
}
405+
395406
/**
396407
* Holds if data flows from `source` to `sink` in zero or more local
397408
* (intra-procedural) steps.

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasedSSA.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,12 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
220220
/**
221221
* Holds if this memory location covers the entire variable.
222222
*/
223-
final predicate coversEntireVariable() {
224-
startBitOffset = 0 and
225-
endBitOffset = var.getIRType().getByteSize() * 8
223+
final predicate coversEntireVariable() { varIRTypeHasBitRange(startBitOffset, endBitOffset) }
224+
225+
pragma[noinline]
226+
private predicate varIRTypeHasBitRange(int start, int end) {
227+
start = 0 and
228+
end = var.getIRType().getByteSize() * 8
226229
}
227230
}
228231

cpp/ql/src/semmle/code/cpp/security/FunctionWithWrappers.qll

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@ abstract class FunctionWithWrappers extends Function {
9494
)
9595
}
9696

97+
/**
98+
* Whether 'func' is a (possibly nested) wrapper function that feeds a parameter at the given index
99+
* through to an interesting parameter of 'this' function.
100+
*
101+
* The 'cause' gives the name of 'this' interesting function and its relevant parameter
102+
* at the end of the call chain.
103+
*
104+
* If there is more than one possible 'cause', a unique one is picked (by lexicographic order).
105+
*/
106+
pragma[nomagic]
107+
private string wrapperFunctionAnyDepthUnique(Function func, int paramIndex) {
108+
result =
109+
toCause(func, paramIndex) + ", which ends up calling " +
110+
min(string targetCause | this.wrapperFunctionAnyDepth(func, paramIndex, targetCause))
111+
}
112+
97113
/**
98114
* Whether 'func' is a (possibly nested) wrapper function that feeds a parameter at the given index
99115
* through to an interesting parameter of 'this' function.
@@ -114,13 +130,7 @@ abstract class FunctionWithWrappers extends Function {
114130
)
115131
or
116132
not this.wrapperFunctionLimitedDepth(func, paramIndex, _, _) and
117-
cause =
118-
min(string targetCause, string possibleCause |
119-
this.wrapperFunctionAnyDepth(func, paramIndex, targetCause) and
120-
possibleCause = toCause(func, paramIndex) + ", which ends up calling " + targetCause
121-
|
122-
possibleCause
123-
)
133+
cause = wrapperFunctionAnyDepthUnique(func, paramIndex)
124134
}
125135

126136
/**

cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
| test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. |
66
| test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. |
77
| test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. |
8+
| test.cpp:55:28:55:33 | call to malloc | This allocation does not include space to null-terminate the string. |
89
| test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. |
910
| test.cpp:71:28:71:33 | call to malloc | This allocation does not include space to null-terminate the string. |
1011
| test.cpp:79:28:79:33 | call to malloc | This allocation does not include space to null-terminate the string. |

cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void decode(char *dest, char *src);
5151
void wdecode(wchar_t *dest, wchar_t *src);
5252

5353
void bad4(char *str) {
54-
// BAD -- zero-termination proved by wprintf (as parameter) [NOT DETECTED]
54+
// BAD -- zero-termination proved by wprintf (as parameter)
5555
char *buffer = (char *)malloc(strlen(str));
5656
decode(buffer, str);
5757
wprintf(L"%s", buffer);
@@ -107,3 +107,19 @@ void bad9(wchar_t *wstr) {
107107
wcscpy(wbuffer, wstr);
108108
delete wbuffer;
109109
}
110+
111+
void good3(char *str) {
112+
// GOOD -- zero-termination not required for this printf
113+
char *buffer = (char *)malloc(strlen(str));
114+
decode(buffer, str);
115+
wprintf(L"%p", buffer);
116+
free(buffer);
117+
}
118+
119+
void good4(char *str) {
120+
// GOOD -- zero-termination not required for this printf
121+
char *buffer = (char *)malloc(strlen(str));
122+
decode(buffer, str);
123+
wprintf(L"%.*s", strlen(str), buffer);
124+
free(buffer);
125+
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,29 @@ class StackAllocArrayCreation : ExplicitArrayCreation<StackAllocArrayCreationExp
9090

9191
public override InitializerExpressionSyntax Initializer => Syntax.Initializer;
9292

93+
protected override void PopulateExpression(TextWriter trapFile)
94+
{
95+
base.PopulateExpression(trapFile);
96+
trapFile.stackalloc_array_creation(this);
97+
}
98+
9399
public static Expression Create(ExpressionNodeInfo info) => new StackAllocArrayCreation(info).TryPopulate();
94100
}
95101

102+
class ImplicitStackAllocArrayCreation : ArrayCreation<ImplicitStackAllocArrayCreationExpressionSyntax>
103+
{
104+
ImplicitStackAllocArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { }
105+
106+
public static Expression Create(ExpressionNodeInfo info) => new ImplicitStackAllocArrayCreation(info).TryPopulate();
107+
108+
protected override void PopulateExpression(TextWriter trapFile)
109+
{
110+
ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1));
111+
trapFile.implicitly_typed_array_creation(this);
112+
trapFile.stackalloc_array_creation(this);
113+
}
114+
}
115+
96116
class ImplicitArrayCreation : ArrayCreation<ImplicitArrayCreationExpressionSyntax>
97117
{
98118
ImplicitArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { }

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ internal static Expression Create(ExpressionNodeInfo info)
207207
case SyntaxKind.StackAllocArrayCreationExpression:
208208
return StackAllocArrayCreation.Create(info);
209209

210+
case SyntaxKind.ImplicitStackAllocArrayCreationExpression:
211+
return ImplicitStackAllocArrayCreation.Create(info);
212+
210213
case SyntaxKind.ArgListExpression:
211214
return ArgList.Create(info);
212215

0 commit comments

Comments
 (0)