Skip to content

Commit f3b4140

Browse files
author
Dave Bartolomeo
committed
C++/C#: Consistent handling of "may" vs. "must" memory accesses
In the IR, some memory accesses are "must" accesses (the entire memory location is always read or written), and some are "may" accesses (some, all, or none of the bits in the location are written). We previously had to special case specific "may" accesses in a few places. This change regularizes our handling of "may" accesses. The `MemoryAccessKind` enumeration now describes only the extent of the access (the set of locations potentially accessed), but does not distinguish "must" from "may". The new predicates `Operand.hasMayMemoryAccess()` and `Instruction.hasResultMayMemoryAccess()` hold when the access is a "may" access. Unaliased SSA now correctly ignores variables that are ever accessed via a "may" access. Aliased SSA now distinguishes `MemoryLocation`s for "may" and "must" accesses. I've refactored `getOverlap()` into the core `getExtentOverlap()`, which considers only the extent, but not the "may" vs. "must", and `getOverlap()`, which tweaks the result of `getExtentOverlap()` based on "may" vs. "must" and read-only locations. When determining the overlap between a `Phi` operand and its definition, we now use the result of the defining `Chi` instruction, if one exists. This gives exact definitions for `Phi` operands for virtual variables.
1 parent 7d48220 commit f3b4140

File tree

19 files changed

+527
-342
lines changed

19 files changed

+527
-342
lines changed

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

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
private newtype TMemoryAccessKind =
22
TIndirectMemoryAccess() or
3-
TIndirectMayMemoryAccess() or
43
TBufferMemoryAccess() or
5-
TBufferMayMemoryAccess() or
64
TEscapedMemoryAccess() or
7-
TEscapedMayMemoryAccess() or
8-
TNonLocalMayMemoryAccess() or
5+
TNonLocalMemoryAccess() or
96
TPhiMemoryAccess() or
107
TUnmodeledMemoryAccess() or
118
TChiTotalMemoryAccess() or
@@ -35,16 +32,6 @@ class IndirectMemoryAccess extends MemoryAccessKind, TIndirectMemoryAccess {
3532
final override predicate usesAddressOperand() { any() }
3633
}
3734

38-
/**
39-
* The operand or result may access some, all, or none of the memory at the address specified by the
40-
* `AddressOperand` on the same instruction.
41-
*/
42-
class IndirectMayMemoryAccess extends MemoryAccessKind, TIndirectMayMemoryAccess {
43-
override string toString() { result = "indirect(may)" }
44-
45-
final override predicate usesAddressOperand() { any() }
46-
}
47-
4835
/**
4936
* The operand or result accesses memory starting at the address specified by the `AddressOperand`
5037
* on the same instruction, accessing a number of consecutive elements given by the
@@ -56,17 +43,6 @@ class BufferMemoryAccess extends MemoryAccessKind, TBufferMemoryAccess {
5643
final override predicate usesAddressOperand() { any() }
5744
}
5845

59-
/**
60-
* The operand or result may access some, all, or none of the memory starting at the address
61-
* specified by the `AddressOperand` on the same instruction, accessing a number of consecutive
62-
* elements given by the `BufferSizeOperand`.
63-
*/
64-
class BufferMayMemoryAccess extends MemoryAccessKind, TBufferMayMemoryAccess {
65-
override string toString() { result = "buffer(may)" }
66-
67-
final override predicate usesAddressOperand() { any() }
68-
}
69-
7046
/**
7147
* The operand or result accesses all memory whose address has escaped.
7248
*/
@@ -75,18 +51,11 @@ class EscapedMemoryAccess extends MemoryAccessKind, TEscapedMemoryAccess {
7551
}
7652

7753
/**
78-
* The operand or result may access all memory whose address has escaped.
79-
*/
80-
class EscapedMayMemoryAccess extends MemoryAccessKind, TEscapedMayMemoryAccess {
81-
override string toString() { result = "escaped(may)" }
82-
}
83-
84-
/**
85-
* The operand or result may access all memory whose address has escaped, other than data on the
86-
* stack frame of the current function.
54+
* The operand or result access all memory whose address has escaped, other than data on the stack
55+
* frame of the current function.
8756
*/
88-
class NonLocalMayMemoryAccess extends MemoryAccessKind, TNonLocalMayMemoryAccess {
89-
override string toString() { result = "nonlocal(may)" }
57+
class NonLocalMemoryAccess extends MemoryAccessKind, TNonLocalMemoryAccess {
58+
override string toString() { result = "nonlocal" }
9059
}
9160

9261
/**

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

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,16 @@ class Instruction extends Construction::TInstruction {
550550
*/
551551
MemoryAccessKind getResultMemoryAccess() { none() }
552552

553+
/**
554+
* Holds if the memory access performed by this instruction's result will not always write to
555+
* every bit in the memory location. This is most commonly used for memory accesses that may or
556+
* may not actually occur depending on runtime state (for example, the write side effect of an
557+
* output parameter that is not written to on all paths), or for accesses where the memory
558+
* location is a conservative estimate of the memory that might actually be accessed at runtime
559+
* (for example, the global side effects of a function call).
560+
*/
561+
predicate hasResultMayMemoryAccess() { none() }
562+
553563
/**
554564
* Gets the operand that holds the memory address to which this instruction stores its
555565
* result, if any. For example, in `m3 = Store r1, r2`, the result of `getResultAddressOperand()`
@@ -1206,9 +1216,9 @@ class SideEffectInstruction extends Instruction {
12061216
class CallSideEffectInstruction extends SideEffectInstruction {
12071217
CallSideEffectInstruction() { getOpcode() instanceof Opcode::CallSideEffect }
12081218

1209-
final override MemoryAccessKind getResultMemoryAccess() {
1210-
result instanceof EscapedMayMemoryAccess
1211-
}
1219+
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
1220+
1221+
final override predicate hasResultMayMemoryAccess() { any() }
12121222
}
12131223

12141224
/**
@@ -1306,9 +1316,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
13061316
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
13071317
}
13081318

1309-
final override MemoryAccessKind getResultMemoryAccess() {
1310-
result instanceof IndirectMayMemoryAccess
1311-
}
1319+
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
1320+
1321+
final override predicate hasResultMayMemoryAccess() { any() }
13121322
}
13131323

13141324
/**
@@ -1318,9 +1328,9 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
13181328
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
13191329
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
13201330

1321-
final override MemoryAccessKind getResultMemoryAccess() {
1322-
result instanceof BufferMayMemoryAccess
1323-
}
1331+
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
1332+
1333+
final override predicate hasResultMayMemoryAccess() { any() }
13241334
}
13251335

13261336
/**
@@ -1332,9 +1342,9 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
13321342
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
13331343
}
13341344

1335-
final override MemoryAccessKind getResultMemoryAccess() {
1336-
result instanceof BufferMayMemoryAccess
1337-
}
1345+
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
1346+
1347+
final override predicate hasResultMayMemoryAccess() { any() }
13381348

13391349
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
13401350
}
@@ -1345,9 +1355,9 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio
13451355
class InlineAsmInstruction extends Instruction {
13461356
InlineAsmInstruction() { getOpcode() instanceof Opcode::InlineAsm }
13471357

1348-
final override MemoryAccessKind getResultMemoryAccess() {
1349-
result instanceof EscapedMayMemoryAccess
1350-
}
1358+
final override MemoryAccessKind getResultMemoryAccess() { result instanceof EscapedMemoryAccess }
1359+
1360+
final override predicate hasResultMayMemoryAccess() { any() }
13511361
}
13521362

13531363
/**

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,16 @@ class MemoryOperand extends Operand {
194194
*/
195195
MemoryAccessKind getMemoryAccess() { none() }
196196

197+
/**
198+
* Holds if the memory access performed by this operand will not always read from every bit in the
199+
* memory location. This is most commonly used for memory accesses that may or may not actually
200+
* occur depending on runtime state (for example, the write side effect of an output parameter
201+
* that is not written to on all paths), or for accesses where the memory location is a
202+
* conservative estimate of the memory that might actually be accessed at runtime (for example,
203+
* the global side effects of a function call).
204+
*/
205+
predicate hasMayMemoryAccess() { none() }
206+
197207
/**
198208
* Returns the operand that holds the memory address from which the current operand loads its
199209
* value, if any. For example, in `r3 = Load r1, m2`, the result of `getAddressOperand()` for `m2`
@@ -397,13 +407,13 @@ class SideEffectOperand extends TypedOperand {
397407

398408
override MemoryAccessKind getMemoryAccess() {
399409
useInstr instanceof AliasedUseInstruction and
400-
result instanceof NonLocalMayMemoryAccess
410+
result instanceof NonLocalMemoryAccess
401411
or
402412
useInstr instanceof CallSideEffectInstruction and
403-
result instanceof EscapedMayMemoryAccess
413+
result instanceof EscapedMemoryAccess
404414
or
405415
useInstr instanceof CallReadSideEffectInstruction and
406-
result instanceof EscapedMayMemoryAccess
416+
result instanceof EscapedMemoryAccess
407417
or
408418
useInstr instanceof IndirectReadSideEffectInstruction and
409419
result instanceof IndirectMemoryAccess
@@ -418,10 +428,22 @@ class SideEffectOperand extends TypedOperand {
418428
result instanceof BufferMemoryAccess
419429
or
420430
useInstr instanceof IndirectMayWriteSideEffectInstruction and
421-
result instanceof IndirectMayMemoryAccess
431+
result instanceof IndirectMemoryAccess
422432
or
423433
useInstr instanceof BufferMayWriteSideEffectInstruction and
424-
result instanceof BufferMayMemoryAccess
434+
result instanceof BufferMemoryAccess
435+
}
436+
437+
final override predicate hasMayMemoryAccess() {
438+
useInstr instanceof AliasedUseInstruction
439+
or
440+
useInstr instanceof CallSideEffectInstruction
441+
or
442+
useInstr instanceof CallReadSideEffectInstruction
443+
or
444+
useInstr instanceof IndirectMayWriteSideEffectInstruction
445+
or
446+
useInstr instanceof BufferMayWriteSideEffectInstruction
425447
}
426448
}
427449

0 commit comments

Comments
 (0)