Skip to content

Commit e60f902

Browse files
author
Dave Bartolomeo
committed
C++/C#: Fix missing virtual variables
The aliased SSA code was assuming that, for every automatic variable, there would be at least one memory access that reads or writes the entire variable. We've encountered a couple cases where that isn't true due to extractor issues. As a workaround, we now always create the `VariableMemoryLocation` for every local variable. I've also added a sanity test to detect this condition in the future. Along the way, I had to fix a perf issue in the PrintIR code. When determining the ID of a result based on line number, we were considering all `Instruction`s generated for a particular line, regardless of whether they were all in the same `IRFunction`. In addition, the predicate had what appeared to be a bad join order that made it take forever on large snapshots. I've scoped it down to just consider `Instruction`s in the same function, and outlined that predicate to fix the join order issue. This causes some numbering changes, but they're for the better. I don't think there was actually any nondeterminism there before, but now the numbering won't depend on the number of instantiations of a template, either.
1 parent b8ee5a6 commit e60f902

File tree

20 files changed

+770
-636
lines changed

20 files changed

+770
-636
lines changed

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ module InstructionSanity {
260260
}
261261
}
262262

263+
/**
264+
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
265+
* `File` and line number. Used for assigning register names when printing IR.
266+
*/
267+
private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) {
268+
exists(Language::Location location |
269+
irFunc = result.getEnclosingIRFunction() and
270+
location = result.getLocation() and
271+
file = location.getFile() and
272+
line = location.getStartLine()
273+
)
274+
}
275+
263276
/**
264277
* Represents a single operation in the IR.
265278
*/
@@ -324,8 +337,8 @@ class Instruction extends Construction::TInstruction {
324337

325338
private int getLineRank() {
326339
this = rank[result](Instruction instr |
327-
instr.getAST().getFile() = getAST().getFile() and
328-
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
340+
instr = getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(),
341+
getLocation().getStartLine())
329342
|
330343
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
331344
)

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,18 @@ private newtype TMemoryLocation =
4141
IntValue endBitOffset, boolean isMayAccess
4242
) {
4343
(
44-
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess) or
44+
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
45+
or
4546
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
47+
or
48+
exists(IRAutomaticVariable autoVar |
49+
// Always create a memory location for the entire variable.
50+
autoVar = var and
51+
type = autoVar.getIRType() and
52+
startBitOffset = 0 and
53+
endBitOffset = type.getByteSize() * 8 and
54+
isMayAccess = false
55+
)
4656
) and
4757
languageType = type.getCanonicalLanguageType()
4858
} or
@@ -78,6 +88,8 @@ abstract class MemoryLocation extends TMemoryLocation {
7888

7989
abstract IRFunction getIRFunction();
8090

91+
abstract Location getLocation();
92+
8193
final IRType getIRType() { result = getType().getIRType() }
8294

8395
abstract predicate isMayAccess();
@@ -141,6 +153,8 @@ class VariableMemoryLocation extends TVariableMemoryLocation, MemoryLocation {
141153

142154
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
143155

156+
final override Location getLocation() { result = var.getLocation() }
157+
144158
final IntValue getStartBitOffset() { result = startBitOffset }
145159

146160
final IntValue getEndBitOffset() { result = endBitOffset }
@@ -208,6 +222,8 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
208222

209223
final override IRFunction getIRFunction() { result = irFunc }
210224

225+
final override Location getLocation() { result = irFunc.getLocation() }
226+
211227
final override string getUniqueId() { result = "{Unknown}" }
212228

213229
final override predicate isMayAccess() { isMayAccess = true }
@@ -233,6 +249,8 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
233249

234250
final override IRFunction getIRFunction() { result = irFunc }
235251

252+
final override Location getLocation() { result = irFunc.getLocation() }
253+
236254
final override string getUniqueId() { result = "{AllNonLocal}" }
237255

238256
final override predicate isMayAccess() { isMayAccess = true }
@@ -255,6 +273,8 @@ class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
255273

256274
final override IRFunction getIRFunction() { result = irFunc }
257275

276+
final override Location getLocation() { result = irFunc.getLocation() }
277+
258278
final override string getUniqueId() { result = " " + toString() }
259279

260280
final override VirtualVariable getVirtualVariable() { result = TAllAliasedMemory(irFunc, false) }

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,4 +885,13 @@ module SSASanity {
885885
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
886886
)
887887
}
888+
889+
query predicate missingVirtualVariableForMemoryLocation(
890+
Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText
891+
) {
892+
not exists(location.getVirtualVariable()) and
893+
func = location.getIRFunction() and
894+
funcText = Language::getIdentityString(func.getFunction()) and
895+
message = "Memory location has no virtual variable in function '$@'."
896+
}
888897
}

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ module InstructionSanity {
260260
}
261261
}
262262

263+
/**
264+
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
265+
* `File` and line number. Used for assigning register names when printing IR.
266+
*/
267+
private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) {
268+
exists(Language::Location location |
269+
irFunc = result.getEnclosingIRFunction() and
270+
location = result.getLocation() and
271+
file = location.getFile() and
272+
line = location.getStartLine()
273+
)
274+
}
275+
263276
/**
264277
* Represents a single operation in the IR.
265278
*/
@@ -324,8 +337,8 @@ class Instruction extends Construction::TInstruction {
324337

325338
private int getLineRank() {
326339
this = rank[result](Instruction instr |
327-
instr.getAST().getFile() = getAST().getFile() and
328-
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
340+
instr = getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(),
341+
getLocation().getStartLine())
329342
|
330343
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
331344
)

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ module InstructionSanity {
260260
}
261261
}
262262

263+
/**
264+
* Gets an `Instruction` that is contained in `IRFunction`, and has a location with the specified
265+
* `File` and line number. Used for assigning register names when printing IR.
266+
*/
267+
private Instruction getAnInstructionAtLine(IRFunction irFunc, Language::File file, int line) {
268+
exists(Language::Location location |
269+
irFunc = result.getEnclosingIRFunction() and
270+
location = result.getLocation() and
271+
file = location.getFile() and
272+
line = location.getStartLine()
273+
)
274+
}
275+
263276
/**
264277
* Represents a single operation in the IR.
265278
*/
@@ -324,8 +337,8 @@ class Instruction extends Construction::TInstruction {
324337

325338
private int getLineRank() {
326339
this = rank[result](Instruction instr |
327-
instr.getAST().getFile() = getAST().getFile() and
328-
instr.getAST().getLocation().getStartLine() = getAST().getLocation().getStartLine()
340+
instr = getAnInstructionAtLine(getEnclosingIRFunction(), getLocation().getFile(),
341+
getLocation().getStartLine())
329342
|
330343
instr order by instr.getBlock().getDisplayIndex(), instr.getDisplayIndexInBlock()
331344
)

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,4 +885,13 @@ module SSASanity {
885885
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
886886
)
887887
}
888+
889+
query predicate missingVirtualVariableForMemoryLocation(
890+
Alias::MemoryLocation location, string message, OldIR::IRFunction func, string funcText
891+
) {
892+
not exists(location.getVirtualVariable()) and
893+
func = location.getIRFunction() and
894+
funcText = Language::getIdentityString(func.getFunction()) and
895+
message = "Memory location has no virtual variable in function '$@'."
896+
}
888897
}

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class MemoryLocation extends TMemoryLocation {
5555

5656
final string toString() { result = var.toString() }
5757

58+
final Language::Location getLocation() { result = var.getLocation() }
59+
60+
final IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
61+
5862
final IRVariable getIRVariable() { result = var }
5963

6064
final VirtualVariable getVirtualVariable() { result = this }

cpp/ql/src/semmle/code/cpp/ir/internal/IRCppLanguage.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class Function = Cpp::Function;
1313

1414
class Location = Cpp::Location;
1515

16+
class File = Cpp::File;
17+
1618
class AST = Cpp::Locatable;
1719

1820
class Type = Cpp::Type;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
multipleOperandMemoryLocations
2+
missingVirtualVariableForMemoryLocation

0 commit comments

Comments
 (0)