Skip to content

Commit ec85f9f

Browse files
authored
Merge pull request github#2797 from rdmarsh2/rdmarsh/cpp/malloc-alias-locations
C++: Support dynamic memory allocations in IR alias analysis
2 parents 28ee756 + ac517b7 commit ec85f9f

File tree

20 files changed

+394
-10
lines changed

20 files changed

+394
-10
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ private newtype TOpcode =
8282
TSizedBufferReadSideEffect() or
8383
TSizedBufferMustWriteSideEffect() or
8484
TSizedBufferMayWriteSideEffect() or
85+
TInitializeDynamicAllocation() or
8586
TChi() or
8687
TInlineAsm() or
8788
TUnreached() or
@@ -695,6 +696,11 @@ module Opcode {
695696
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
696697
}
697698

699+
class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode,
700+
TInitializeDynamicAllocation {
701+
final override string toString() { result = "InitializeDynamicAllocation" }
702+
}
703+
698704
class Chi extends Opcode, TChi {
699705
final override string toString() { result = "Chi" }
700706

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
13501350
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
13511351
}
13521352

1353+
/**
1354+
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
1355+
* call to `malloc`.
1356+
*/
1357+
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
1358+
InitializeDynamicAllocationInstruction() {
1359+
getOpcode() instanceof Opcode::InitializeDynamicAllocation
1360+
}
1361+
1362+
/**
1363+
* Gets the address of the allocation this instruction is initializing.
1364+
*/
1365+
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
1366+
1367+
/**
1368+
* Gets the operand for the allocation this instruction is initializing.
1369+
*/
1370+
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
1371+
}
1372+
13531373
/**
13541374
* An instruction representing a GNU or MSVC inline assembly statement.
13551375
*/

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ private newtype TAllocation =
77
TVariableAllocation(IRVariable var) or
88
TIndirectParameterAllocation(IRAutomaticUserVariable var) {
99
exists(InitializeIndirectionInstruction instr | instr.getIRVariable() = var)
10+
} or
11+
TDynamicAllocation(CallInstruction call) {
12+
exists(InitializeDynamicAllocationInstruction instr | instr.getPrimaryInstruction() = call)
1013
}
1114

1215
/**
@@ -95,3 +98,29 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
9598

9699
final override predicate alwaysEscapes() { none() }
97100
}
101+
102+
class DynamicAllocation extends Allocation, TDynamicAllocation {
103+
CallInstruction call;
104+
105+
DynamicAllocation() { this = TDynamicAllocation(call) }
106+
107+
final override string toString() {
108+
result = call.toString() + " at " + call.getLocation() // This isn't performant, but it's only used in test/dump code right now.
109+
}
110+
111+
final override CallInstruction getABaseInstruction() { result = call }
112+
113+
final override IRFunction getEnclosingIRFunction() { result = call.getEnclosingIRFunction() }
114+
115+
final override Language::Location getLocation() { result = call.getLocation() }
116+
117+
final override string getUniqueId() { result = call.getUniqueId() }
118+
119+
final override IRType getIRType() { result instanceof IRUnknownType }
120+
121+
final override predicate isReadOnly() { none() }
122+
123+
final override predicate isAlwaysAllocatedOnStack() { none() }
124+
125+
final override predicate alwaysEscapes() { none() }
126+
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,12 @@ private newtype TMemoryLocation =
6868
) and
6969
languageType = type.getCanonicalLanguageType()
7070
} or
71-
TEntireAllocationMemoryLocation(IndirectParameterAllocation var, boolean isMayAccess) {
72-
isMayAccess = false or isMayAccess = true
71+
TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) {
72+
(
73+
var instanceof IndirectParameterAllocation or
74+
var instanceof DynamicAllocation
75+
) and
76+
(isMayAccess = false or isMayAccess = true)
7377
} or
7478
TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
7579
isMayAccess = false or isMayAccess = true

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
13501350
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
13511351
}
13521352

1353+
/**
1354+
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
1355+
* call to `malloc`.
1356+
*/
1357+
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
1358+
InitializeDynamicAllocationInstruction() {
1359+
getOpcode() instanceof Opcode::InitializeDynamicAllocation
1360+
}
1361+
1362+
/**
1363+
* Gets the address of the allocation this instruction is initializing.
1364+
*/
1365+
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
1366+
1367+
/**
1368+
* Gets the operand for the allocation this instruction is initializing.
1369+
*/
1370+
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
1371+
}
1372+
13531373
/**
13541374
* An instruction representing a GNU or MSVC inline assembly statement.
13551375
*/

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,32 @@ class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
341341
)
342342
}
343343

344-
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) { none() }
345-
346-
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
344+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType type) {
345+
expr.getTarget() instanceof AllocationFunction and
346+
opcode instanceof Opcode::InitializeDynamicAllocation and
347+
tag = OnlyInstructionTag() and
348+
type = getUnknownType()
349+
}
347350

348-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
351+
override Instruction getFirstInstruction() {
352+
if expr.getTarget() instanceof AllocationFunction
353+
then result = getInstruction(OnlyInstructionTag())
354+
else result = getChild(0).getFirstInstruction()
355+
}
349356

350-
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
357+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
358+
tag = OnlyInstructionTag() and
359+
kind = gotoEdge() and
360+
expr.getTarget() instanceof AllocationFunction and
361+
if exists(getChild(0))
362+
then result = getChild(0).getFirstInstruction()
363+
else result = getParent().getChildSuccessor(this)
364+
}
351365

352-
override CppType getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
353-
none()
366+
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
367+
tag = OnlyInstructionTag() and
368+
operandTag = addressOperand() and
369+
result = getPrimaryInstructionForSideEffect(OnlyInstructionTag())
354370
}
355371

356372
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,9 @@ newtype TTranslatedElement =
411411
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
412412
// The side effects of a `Call`
413413
TTranslatedSideEffects(Call expr) {
414-
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or expr instanceof ConstructorCall
414+
exists(TTranslatedArgumentSideEffect(expr, _, _, _)) or
415+
expr instanceof ConstructorCall or
416+
expr.getTarget() instanceof AllocationFunction
415417
} or // A precise side effect of an argument to a `Call`
416418
TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) {
417419
(

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,26 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
13501350
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
13511351
}
13521352

1353+
/**
1354+
* An instruction representing the initial value of newly allocated memory, e.g. the result of a
1355+
* call to `malloc`.
1356+
*/
1357+
class InitializeDynamicAllocationInstruction extends SideEffectInstruction {
1358+
InitializeDynamicAllocationInstruction() {
1359+
getOpcode() instanceof Opcode::InitializeDynamicAllocation
1360+
}
1361+
1362+
/**
1363+
* Gets the address of the allocation this instruction is initializing.
1364+
*/
1365+
final AddressOperand getAllocationAddressOperand() { result = getAnOperand() }
1366+
1367+
/**
1368+
* Gets the operand for the allocation this instruction is initializing.
1369+
*/
1370+
final Instruction getAllocationAddress() { result = getAllocationAddressOperand().getDef() }
1371+
}
1372+
13531373
/**
13541374
* An instruction representing a GNU or MSVC inline assembly statement.
13551375
*/

cpp/ql/test/library-tests/dataflow/security-taint/tainted.expected

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,18 @@
5252
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
5353
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
5454
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | |
55+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:8:24:8:25 | s1 | |
56+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
57+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
58+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:17:83:24 | userName | |
59+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:33 | call to getenv | |
60+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:83:28:83:46 | (const char *)... | |
61+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | |
62+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:2:86:7 | call to strcpy | |
63+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | |
64+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:15:86:22 | userName | |
65+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:6:88:27 | ! ... | |
66+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:12 | call to strcmp | |
67+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:7:88:27 | (bool)... | |
68+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | (const char *)... | |
69+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:88:14:88:17 | copy | |

cpp/ql/test/library-tests/dataflow/security-taint/tainted_diff.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@
88
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | AST only |
99
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | AST only |
1010
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | AST only |
11+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only |
12+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:85:8:85:11 | copy | AST only |
13+
| test.cpp:83:28:83:33 | call to getenv | test.cpp:86:9:86:12 | copy | AST only |

0 commit comments

Comments
 (0)