CodeQL library for C/C++
codeql/cpp-all 1.3.1-dev (changelog, source)
Search

Predicate Cached::getInstructionSuccessor

This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node, that node is its successor in the new successor relation, and the Chi node’s successors are the new instructions generated from the successors of the old instruction.

Furthermore, the entry block is augmented with UninitializedGroup instructions and Chi instructions. For example, consider this example:

int x, y;
int* p;
if(b) {
  p = &x;
  escape(&x);
} else {
  p = &y;
}
*p = 42;

int z, w;
int* q;
if(b) {
  q = &z;
} else {
  q = &w;
}
*q = 43;

the unaliased IR for the entry block of this snippet is:

v1(void)         = EnterFunction          :
m1(unknown)      = AliasedDefinition      :
m2(unknown)      = InitializeNonLocal     :
r1(glval<bool>)  = VariableAddress[b]     :
m3(bool)         = InitializeParameter[b] : &:r1
r2(glval<int>)   = VariableAddress[x]     :
m4(int)          = Uninitialized[x]       : &:r2
r3(glval<int>)   = VariableAddress[y]     :
m5(int)          = Uninitialized[y]       : &:r3
r4(glval<int *>) = VariableAddress[p]     :
m6(int *)        = Uninitialized[p]       : &:r4
r5(glval<bool>)  = VariableAddress[b]     :
r6(bool)         = Load[b]                : &:r5, m3
v2(void)         = ConditionalBranch      : r6

and we need to transform this to aliased IR by inserting an UninitializedGroup instruction for every VariableGroup memory location in the function. Furthermore, if the VariableGroup memory location contains an allocation that escapes we need to insert a Chi that writes the memory produced by UninitializedGroup into {AllAliasedMemory}. For the above snippet we then end up with:

v1(void)         = EnterFunction           :
m2(unknown)      = AliasedDefinition       :
m3(unknown)      = InitializeNonLocal      :
m4(unknown)      = Chi                     : total:m2, partial:m3
m5(int)          = UninitializedGroup[x,y] :
m6(unknown)      = Chi                     : total:m4, partial:m5
m7(int)          = UninitializedGroup[w,z] :
r1(glval<bool>)  = VariableAddress[b]      :
m8(bool)         = InitializeParameter[b]  : &:r1
r2(glval<int>)   = VariableAddress[x]      :
m10(int)         = Uninitialized[x]       : &:r2
m11(unknown)     = Chi                    : total:m6, partial:m10
r3(glval<int>)   = VariableAddress[y]      :
m12(int)         = Uninitialized[y]       : &:r3
m13(unknown)     = Chi                    : total:m11, partial:m12
r4(glval<int *>) = VariableAddress[p]      :
m14(int *)       = Uninitialized[p]       : &:r4
r5(glval<bool>)  = VariableAddress[b]      :
r6(bool)         = Load[b]                 : &:r5, m8
v2(void)         = ConditionalBranch       : r6

Here, the group {x, y} contains an allocation that escapes (x), so there is a Chi after the UninitializedGroup that initializes the memory for the VariableGroup containing x. None of the allocations in {w, z} escape so there is no Chi following that the UninitializedGroup that initializes the memory of {w, z}.

Import path

import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind)