Merge branch 'master' of github.com:Semmle/ql into rdmarsh/cpp/ir-constructor-side-effects

This commit is contained in:
Robert Marsh
2019-11-08 14:06:36 -08:00
23 changed files with 500 additions and 270 deletions

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -818,14 +818,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {

View File

@@ -308,6 +308,10 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
instr.(VariableAddressInstruction).getIRVariable() = var and
bitOffset = 0
or
// A string literal is just a special read-only global variable.
instr.(StringConstantInstruction).getIRVariable() = var and
bitOffset = 0
or
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
operand = instr.getAnOperand() and
// If an operand is propagated, then the result points to the same variable,

View File

@@ -210,17 +210,21 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
def instanceof UnknownVirtualVariable and
result instanceof MustTotallyOverlap
or
// An UnknownMemoryLocation may partially overlap any Location within the same virtual variable.
// An UnknownMemoryLocation may partially overlap any Location within the same virtual variable,
// unless the location is read-only.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownMemoryLocation and
result instanceof MayPartiallyOverlap
result instanceof MayPartiallyOverlap and
not use.(VariableMemoryLocation).getVariable().isReadOnly()
or
// An UnknownNonLocalMemoryLocation may partially overlap any location within the same virtual
// variable, except a local variable.
// variable, except a local variable or read-only variable.
def.getVirtualVariable() = use.getVirtualVariable() and
def instanceof UnknownNonLocalMemoryLocation and
result instanceof MayPartiallyOverlap and
not use.(VariableMemoryLocation).getVariable() instanceof IRAutomaticVariable
not exists(IRVariable var | var = use.(VariableMemoryLocation).getVariable() |
var instanceof IRAutomaticVariable or var.isReadOnly()
)
or
exists(VariableMemoryLocation defVariableLocation |
defVariableLocation = def and

View File

@@ -341,11 +341,6 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)

View File

@@ -9,4 +9,10 @@ newtype TIRVariable =
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
Construction::hasTempVariable(func, ast, tag, type)
} or
TIRStringLiteral(
Language::Function func, Language::AST ast, Language::LanguageType type,
Language::StringLiteral literal
) {
Construction::hasStringLiteral(func, ast, type, literal)
}

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -818,14 +818,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {

View File

@@ -44,6 +44,13 @@ private module Cached {
)
}
cached
predicate hasStringLiteral(Function func, Locatable ast, CppType type, StringLiteral literal) {
literal = ast and
literal.getEnclosingFunction() = func and
getTypeForPRValue(literal.getType()) = type
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
@@ -234,8 +241,14 @@ private module Cached {
cached
IRVariable getInstructionVariable(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)
.getInstructionVariable(getInstructionTag(instruction))
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
@@ -266,12 +279,6 @@ private module Cached {
)
}
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)
.getInstructionStringLiteral(getInstructionTag(instruction))
}
cached
BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -818,14 +818,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {

View File

@@ -308,6 +308,10 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
instr.(VariableAddressInstruction).getIRVariable() = var and
bitOffset = 0
or
// A string literal is just a special read-only global variable.
instr.(StringConstantInstruction).getIRVariable() = var and
bitOffset = 0
or
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |
operand = instr.getAnOperand() and
// If an operand is propagated, then the result points to the same variable,

View File

@@ -341,11 +341,6 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)

View File

@@ -952,81 +952,107 @@ ssa.cpp:
# 213| v0_69(void) = AliasedUse : ~m0_1
# 213| v0_70(void) = ExitFunction :
# 226| void Constructible::Constructible(int)
# 226| char StringLiteralAliasing()
# 226| Block 0
# 226| v0_0(void) = EnterFunction :
# 226| m0_1(unknown) = AliasedDefinition :
# 226| mu0_2(unknown) = UnmodeledDefinition :
# 226| r0_3(glval<Constructible>) = InitializeThis :
# 226| r0_4(glval<int>) = VariableAddress[x] :
# 226| m0_5(int) = InitializeParameter[x] : &:r0_4
# 226| v0_6(void) = NoOp :
# 226| v0_7(void) = ReturnVoid :
# 226| v0_8(void) = UnmodeledUse : mu*
# 226| v0_9(void) = AliasedUse : ~m0_1
# 226| v0_10(void) = ExitFunction :
# 226| v0_0(void) = EnterFunction :
# 226| m0_1(unknown) = AliasedDefinition :
# 226| mu0_2(unknown) = UnmodeledDefinition :
# 227| r0_3(glval<unknown>) = FunctionAddress[ExternalFunc] :
# 227| v0_4(void) = Call : func:r0_3
# 227| m0_5(unknown) = ^CallSideEffect : ~m0_1
# 227| m0_6(unknown) = Chi : total:m0_1, partial:m0_5
# 229| r0_7(glval<char *>) = VariableAddress[s] :
# 229| r0_8(glval<char[8]>) = StringConstant["Literal"] :
# 229| r0_9(char *) = Convert : r0_8
# 229| m0_10(char *) = Store : &:r0_7, r0_9
# 230| r0_11(glval<char>) = VariableAddress[#return] :
# 230| r0_12(glval<char *>) = VariableAddress[s] :
# 230| r0_13(char *) = Load : &:r0_12, m0_10
# 230| r0_14(int) = Constant[2] :
# 230| r0_15(glval<char>) = PointerAdd[1] : r0_13, r0_14
# 230| r0_16(char) = Load : &:r0_15, ~m0_1
# 230| m0_17(char) = Store : &:r0_11, r0_16
# 226| r0_18(glval<char>) = VariableAddress[#return] :
# 226| v0_19(void) = ReturnValue : &:r0_18, m0_17
# 226| v0_20(void) = UnmodeledUse : mu*
# 226| v0_21(void) = AliasedUse : ~m0_6
# 226| v0_22(void) = ExitFunction :
# 227| void Constructible::g()
# 227| Block 0
# 227| v0_0(void) = EnterFunction :
# 227| m0_1(unknown) = AliasedDefinition :
# 227| mu0_2(unknown) = UnmodeledDefinition :
# 227| r0_3(glval<Constructible>) = InitializeThis :
# 227| v0_4(void) = NoOp :
# 227| v0_5(void) = ReturnVoid :
# 227| v0_6(void) = UnmodeledUse : mu*
# 227| v0_7(void) = AliasedUse : ~m0_1
# 227| v0_8(void) = ExitFunction :
# 235| void Constructible::Constructible(int)
# 235| Block 0
# 235| v0_0(void) = EnterFunction :
# 235| m0_1(unknown) = AliasedDefinition :
# 235| mu0_2(unknown) = UnmodeledDefinition :
# 235| r0_3(glval<Constructible>) = InitializeThis :
# 235| r0_4(glval<int>) = VariableAddress[x] :
# 235| m0_5(int) = InitializeParameter[x] : &:r0_4
# 235| v0_6(void) = NoOp :
# 235| v0_7(void) = ReturnVoid :
# 235| v0_8(void) = UnmodeledUse : mu*
# 235| v0_9(void) = AliasedUse : ~m0_1
# 235| v0_10(void) = ExitFunction :
# 230| void ExplicitConstructorCalls()
# 230| Block 0
# 230| v0_0(void) = EnterFunction :
# 230| m0_1(unknown) = AliasedDefinition :
# 230| mu0_2(unknown) = UnmodeledDefinition :
# 231| r0_3(glval<Constructible>) = VariableAddress[c] :
# 231| m0_4(Constructible) = Uninitialized[c] : &:r0_3
# 231| r0_5(glval<unknown>) = FunctionAddress[Constructible] :
# 231| r0_6(int) = Constant[1] :
# 231| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6
# 231| m0_8(unknown) = ^CallSideEffect : ~m0_1
# 231| m0_9(unknown) = Chi : total:m0_1, partial:m0_8
# 231| m0_10(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3
# 231| m0_11(Constructible) = Chi : total:m0_4, partial:m0_10
# 232| r0_12(glval<Constructible>) = VariableAddress[c] :
# 232| r0_13(glval<unknown>) = FunctionAddress[g] :
# 232| v0_14(void) = Call : func:r0_13, this:r0_12
# 232| m0_15(unknown) = ^CallSideEffect : ~m0_9
# 232| m0_16(unknown) = Chi : total:m0_9, partial:m0_15
# 232| v0_17(void) = ^BufferReadSideEffect[-1] : &:r0_12, ~m0_11
# 232| m0_18(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_12
# 232| m0_19(Constructible) = Chi : total:m0_11, partial:m0_18
# 233| r0_20(glval<Constructible>) = VariableAddress[c] :
# 233| r0_21(glval<unknown>) = FunctionAddress[g] :
# 233| v0_22(void) = Call : func:r0_21, this:r0_20
# 233| m0_23(unknown) = ^CallSideEffect : ~m0_16
# 233| m0_24(unknown) = Chi : total:m0_16, partial:m0_23
# 233| v0_25(void) = ^BufferReadSideEffect[-1] : &:r0_20, ~m0_19
# 233| m0_26(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_20
# 233| m0_27(Constructible) = Chi : total:m0_19, partial:m0_26
# 234| r0_28(glval<Constructible>) = VariableAddress[c2] :
# 234| m0_29(Constructible) = Uninitialized[c2] : &:r0_28
# 234| r0_30(glval<unknown>) = FunctionAddress[Constructible] :
# 234| r0_31(int) = Constant[2] :
# 234| v0_32(void) = Call : func:r0_30, this:r0_28, 0:r0_31
# 234| m0_33(unknown) = ^CallSideEffect : ~m0_24
# 234| m0_34(unknown) = Chi : total:m0_24, partial:m0_33
# 234| m0_35(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_28
# 234| m0_36(Constructible) = Chi : total:m0_29, partial:m0_35
# 235| r0_37(glval<Constructible>) = VariableAddress[c2] :
# 235| r0_38(glval<unknown>) = FunctionAddress[g] :
# 235| v0_39(void) = Call : func:r0_38, this:r0_37
# 235| m0_40(unknown) = ^CallSideEffect : ~m0_34
# 235| m0_41(unknown) = Chi : total:m0_34, partial:m0_40
# 235| v0_42(void) = ^BufferReadSideEffect[-1] : &:r0_37, ~m0_36
# 235| m0_43(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_37
# 235| m0_44(Constructible) = Chi : total:m0_36, partial:m0_43
# 236| v0_45(void) = NoOp :
# 230| v0_46(void) = ReturnVoid :
# 230| v0_47(void) = UnmodeledUse : mu*
# 230| v0_48(void) = AliasedUse : ~m0_41
# 230| v0_49(void) = ExitFunction :
# 236| void Constructible::g()
# 236| Block 0
# 236| v0_0(void) = EnterFunction :
# 236| m0_1(unknown) = AliasedDefinition :
# 236| mu0_2(unknown) = UnmodeledDefinition :
# 236| r0_3(glval<Constructible>) = InitializeThis :
# 236| v0_4(void) = NoOp :
# 236| v0_5(void) = ReturnVoid :
# 236| v0_6(void) = UnmodeledUse : mu*
# 236| v0_7(void) = AliasedUse : ~m0_1
# 236| v0_8(void) = ExitFunction :
# 239| void ExplicitConstructorCalls()
# 239| Block 0
# 239| v0_0(void) = EnterFunction :
# 239| m0_1(unknown) = AliasedDefinition :
# 239| mu0_2(unknown) = UnmodeledDefinition :
# 240| r0_3(glval<Constructible>) = VariableAddress[c] :
# 240| m0_4(Constructible) = Uninitialized[c] : &:r0_3
# 240| r0_5(glval<unknown>) = FunctionAddress[Constructible] :
# 240| r0_6(int) = Constant[1] :
# 240| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6
# 240| m0_8(unknown) = ^CallSideEffect : ~m0_1
# 240| m0_9(unknown) = Chi : total:m0_1, partial:m0_8
# 240| m0_10(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3
# 240| m0_11(Constructible) = Chi : total:m0_4, partial:m0_10
# 241| r0_12(glval<Constructible>) = VariableAddress[c] :
# 241| r0_13(glval<unknown>) = FunctionAddress[g] :
# 241| v0_14(void) = Call : func:r0_13, this:r0_12
# 241| m0_15(unknown) = ^CallSideEffect : ~m0_9
# 241| m0_16(unknown) = Chi : total:m0_9, partial:m0_15
# 241| v0_17(void) = ^BufferReadSideEffect[-1] : &:r0_12, ~m0_11
# 241| m0_18(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_12
# 241| m0_19(Constructible) = Chi : total:m0_11, partial:m0_18
# 242| r0_20(glval<Constructible>) = VariableAddress[c] :
# 242| r0_21(glval<unknown>) = FunctionAddress[g] :
# 242| v0_22(void) = Call : func:r0_21, this:r0_20
# 242| m0_23(unknown) = ^CallSideEffect : ~m0_16
# 242| m0_24(unknown) = Chi : total:m0_16, partial:m0_23
# 242| v0_25(void) = ^BufferReadSideEffect[-1] : &:r0_20, ~m0_19
# 242| m0_26(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_20
# 242| m0_27(Constructible) = Chi : total:m0_19, partial:m0_26
# 243| r0_28(glval<Constructible>) = VariableAddress[c2] :
# 243| m0_29(Constructible) = Uninitialized[c2] : &:r0_28
# 243| r0_30(glval<unknown>) = FunctionAddress[Constructible] :
# 243| r0_31(int) = Constant[2] :
# 243| v0_32(void) = Call : func:r0_30, this:r0_28, 0:r0_31
# 243| m0_33(unknown) = ^CallSideEffect : ~m0_24
# 243| m0_34(unknown) = Chi : total:m0_24, partial:m0_33
# 243| m0_35(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_28
# 243| m0_36(Constructible) = Chi : total:m0_29, partial:m0_35
# 244| r0_37(glval<Constructible>) = VariableAddress[c2] :
# 244| r0_38(glval<unknown>) = FunctionAddress[g] :
# 244| v0_39(void) = Call : func:r0_38, this:r0_37
# 244| m0_40(unknown) = ^CallSideEffect : ~m0_34
# 244| m0_41(unknown) = Chi : total:m0_34, partial:m0_40
# 244| v0_42(void) = ^BufferReadSideEffect[-1] : &:r0_37, ~m0_36
# 244| m0_43(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_37
# 244| m0_44(Constructible) = Chi : total:m0_36, partial:m0_43
# 245| v0_45(void) = NoOp :
# 239| v0_46(void) = ReturnVoid :
# 239| v0_47(void) = UnmodeledUse : mu*
# 239| v0_48(void) = AliasedUse : ~m0_41
# 239| v0_49(void) = ExitFunction :

View File

@@ -221,6 +221,15 @@ void InitArray() {
char f[3] = { 0 };
}
extern void ExternalFunc();
char StringLiteralAliasing() {
ExternalFunc();
const char* s = "Literal";
return s[2]; // Should be defined by `AliasedDefinition`, not `Chi` or `CallSideEffect`.
}
class Constructible {
public:
Constructible(int x) {};

View File

@@ -908,71 +908,96 @@ ssa.cpp:
# 213| v0_61(void) = AliasedUse : ~mu0_2
# 213| v0_62(void) = ExitFunction :
# 226| void Constructible::Constructible(int)
# 226| char StringLiteralAliasing()
# 226| Block 0
# 226| v0_0(void) = EnterFunction :
# 226| mu0_1(unknown) = AliasedDefinition :
# 226| mu0_2(unknown) = UnmodeledDefinition :
# 226| r0_3(glval<Constructible>) = InitializeThis :
# 226| r0_4(glval<int>) = VariableAddress[x] :
# 226| m0_5(int) = InitializeParameter[x] : &:r0_4
# 226| v0_6(void) = NoOp :
# 226| v0_7(void) = ReturnVoid :
# 226| v0_8(void) = UnmodeledUse : mu*
# 226| v0_9(void) = AliasedUse : ~mu0_2
# 226| v0_10(void) = ExitFunction :
# 226| v0_0(void) = EnterFunction :
# 226| mu0_1(unknown) = AliasedDefinition :
# 226| mu0_2(unknown) = UnmodeledDefinition :
# 227| r0_3(glval<unknown>) = FunctionAddress[ExternalFunc] :
# 227| v0_4(void) = Call : func:r0_3
# 227| mu0_5(unknown) = ^CallSideEffect : ~mu0_2
# 229| r0_6(glval<char *>) = VariableAddress[s] :
# 229| r0_7(glval<char[8]>) = StringConstant["Literal"] :
# 229| r0_8(char *) = Convert : r0_7
# 229| m0_9(char *) = Store : &:r0_6, r0_8
# 230| r0_10(glval<char>) = VariableAddress[#return] :
# 230| r0_11(glval<char *>) = VariableAddress[s] :
# 230| r0_12(char *) = Load : &:r0_11, m0_9
# 230| r0_13(int) = Constant[2] :
# 230| r0_14(glval<char>) = PointerAdd[1] : r0_12, r0_13
# 230| r0_15(char) = Load : &:r0_14, ~mu0_2
# 230| m0_16(char) = Store : &:r0_10, r0_15
# 226| r0_17(glval<char>) = VariableAddress[#return] :
# 226| v0_18(void) = ReturnValue : &:r0_17, m0_16
# 226| v0_19(void) = UnmodeledUse : mu*
# 226| v0_20(void) = AliasedUse : ~mu0_2
# 226| v0_21(void) = ExitFunction :
# 227| void Constructible::g()
# 227| Block 0
# 227| v0_0(void) = EnterFunction :
# 227| mu0_1(unknown) = AliasedDefinition :
# 227| mu0_2(unknown) = UnmodeledDefinition :
# 227| r0_3(glval<Constructible>) = InitializeThis :
# 227| v0_4(void) = NoOp :
# 227| v0_5(void) = ReturnVoid :
# 227| v0_6(void) = UnmodeledUse : mu*
# 227| v0_7(void) = AliasedUse : ~mu0_2
# 227| v0_8(void) = ExitFunction :
# 235| void Constructible::Constructible(int)
# 235| Block 0
# 235| v0_0(void) = EnterFunction :
# 235| mu0_1(unknown) = AliasedDefinition :
# 235| mu0_2(unknown) = UnmodeledDefinition :
# 235| r0_3(glval<Constructible>) = InitializeThis :
# 235| r0_4(glval<int>) = VariableAddress[x] :
# 235| m0_5(int) = InitializeParameter[x] : &:r0_4
# 235| v0_6(void) = NoOp :
# 235| v0_7(void) = ReturnVoid :
# 235| v0_8(void) = UnmodeledUse : mu*
# 235| v0_9(void) = AliasedUse : ~mu0_2
# 235| v0_10(void) = ExitFunction :
# 230| void ExplicitConstructorCalls()
# 230| Block 0
# 230| v0_0(void) = EnterFunction :
# 230| mu0_1(unknown) = AliasedDefinition :
# 230| mu0_2(unknown) = UnmodeledDefinition :
# 231| r0_3(glval<Constructible>) = VariableAddress[c] :
# 231| mu0_4(Constructible) = Uninitialized[c] : &:r0_3
# 231| r0_5(glval<unknown>) = FunctionAddress[Constructible] :
# 231| r0_6(int) = Constant[1] :
# 231| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6
# 231| mu0_8(unknown) = ^CallSideEffect : ~mu0_2
# 231| mu0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3
# 232| r0_10(glval<Constructible>) = VariableAddress[c] :
# 232| r0_11(glval<unknown>) = FunctionAddress[g] :
# 232| v0_12(void) = Call : func:r0_11, this:r0_10
# 232| mu0_13(unknown) = ^CallSideEffect : ~mu0_2
# 232| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_10, ~mu0_2
# 232| mu0_15(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10
# 233| r0_16(glval<Constructible>) = VariableAddress[c] :
# 233| r0_17(glval<unknown>) = FunctionAddress[g] :
# 233| v0_18(void) = Call : func:r0_17, this:r0_16
# 233| mu0_19(unknown) = ^CallSideEffect : ~mu0_2
# 233| v0_20(void) = ^BufferReadSideEffect[-1] : &:r0_16, ~mu0_2
# 233| mu0_21(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_16
# 234| r0_22(glval<Constructible>) = VariableAddress[c2] :
# 234| mu0_23(Constructible) = Uninitialized[c2] : &:r0_22
# 234| r0_24(glval<unknown>) = FunctionAddress[Constructible] :
# 234| r0_25(int) = Constant[2] :
# 234| v0_26(void) = Call : func:r0_24, this:r0_22, 0:r0_25
# 234| mu0_27(unknown) = ^CallSideEffect : ~mu0_2
# 234| mu0_28(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_22
# 235| r0_29(glval<Constructible>) = VariableAddress[c2] :
# 235| r0_30(glval<unknown>) = FunctionAddress[g] :
# 235| v0_31(void) = Call : func:r0_30, this:r0_29
# 235| mu0_32(unknown) = ^CallSideEffect : ~mu0_2
# 235| v0_33(void) = ^BufferReadSideEffect[-1] : &:r0_29, ~mu0_2
# 235| mu0_34(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_29
# 236| v0_35(void) = NoOp :
# 230| v0_36(void) = ReturnVoid :
# 230| v0_37(void) = UnmodeledUse : mu*
# 230| v0_38(void) = AliasedUse : ~mu0_2
# 230| v0_39(void) = ExitFunction :
# 236| void Constructible::g()
# 236| Block 0
# 236| v0_0(void) = EnterFunction :
# 236| mu0_1(unknown) = AliasedDefinition :
# 236| mu0_2(unknown) = UnmodeledDefinition :
# 236| r0_3(glval<Constructible>) = InitializeThis :
# 236| v0_4(void) = NoOp :
# 236| v0_5(void) = ReturnVoid :
# 236| v0_6(void) = UnmodeledUse : mu*
# 236| v0_7(void) = AliasedUse : ~mu0_2
# 236| v0_8(void) = ExitFunction :
# 239| void ExplicitConstructorCalls()
# 239| Block 0
# 239| v0_0(void) = EnterFunction :
# 239| mu0_1(unknown) = AliasedDefinition :
# 239| mu0_2(unknown) = UnmodeledDefinition :
# 240| r0_3(glval<Constructible>) = VariableAddress[c] :
# 240| mu0_4(Constructible) = Uninitialized[c] : &:r0_3
# 240| r0_5(glval<unknown>) = FunctionAddress[Constructible] :
# 240| r0_6(int) = Constant[1] :
# 240| v0_7(void) = Call : func:r0_5, this:r0_3, 0:r0_6
# 240| mu0_8(unknown) = ^CallSideEffect : ~mu0_2
# 240| mu0_9(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_3
# 241| r0_10(glval<Constructible>) = VariableAddress[c] :
# 241| r0_11(glval<unknown>) = FunctionAddress[g] :
# 241| v0_12(void) = Call : func:r0_11, this:r0_10
# 241| mu0_13(unknown) = ^CallSideEffect : ~mu0_2
# 241| v0_14(void) = ^BufferReadSideEffect[-1] : &:r0_10, ~mu0_2
# 241| mu0_15(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_10
# 242| r0_16(glval<Constructible>) = VariableAddress[c] :
# 242| r0_17(glval<unknown>) = FunctionAddress[g] :
# 242| v0_18(void) = Call : func:r0_17, this:r0_16
# 242| mu0_19(unknown) = ^CallSideEffect : ~mu0_2
# 242| v0_20(void) = ^BufferReadSideEffect[-1] : &:r0_16, ~mu0_2
# 242| mu0_21(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_16
# 243| r0_22(glval<Constructible>) = VariableAddress[c2] :
# 243| mu0_23(Constructible) = Uninitialized[c2] : &:r0_22
# 243| r0_24(glval<unknown>) = FunctionAddress[Constructible] :
# 243| r0_25(int) = Constant[2] :
# 243| v0_26(void) = Call : func:r0_24, this:r0_22, 0:r0_25
# 243| mu0_27(unknown) = ^CallSideEffect : ~mu0_2
# 243| mu0_28(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_22
# 244| r0_29(glval<Constructible>) = VariableAddress[c2] :
# 244| r0_30(glval<unknown>) = FunctionAddress[g] :
# 244| v0_31(void) = Call : func:r0_30, this:r0_29
# 244| mu0_32(unknown) = ^CallSideEffect : ~mu0_2
# 244| v0_33(void) = ^BufferReadSideEffect[-1] : &:r0_29, ~mu0_2
# 244| mu0_34(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r0_29
# 245| v0_35(void) = NoOp :
# 239| v0_36(void) = ReturnVoid :
# 239| v0_37(void) = UnmodeledUse : mu*
# 239| v0_38(void) = AliasedUse : ~mu0_2
# 239| v0_39(void) = ExitFunction :

View File

@@ -9,4 +9,10 @@ newtype TIRVariable =
Language::Function func, Language::AST ast, TempVariableTag tag, Language::LanguageType type
) {
Construction::hasTempVariable(func, ast, tag, type)
} or
TIRStringLiteral(
Language::Function func, Language::AST ast, Language::LanguageType type,
Language::StringLiteral literal
) {
Construction::hasStringLiteral(func, ast, type, literal)
}

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -818,14 +818,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {

View File

@@ -52,6 +52,15 @@ private module Cached {
)
}
cached
predicate hasStringLiteral(
Callable callable, Language::AST ast, CSharpType type, StringLiteral literal
) {
literal = ast and
literal.getEnclosingCallable() = callable and
getTypeForPRValue(literal.getType()) = type
}
cached
predicate hasModeledMemoryResult(Instruction instruction) { none() }
@@ -232,8 +241,14 @@ private module Cached {
cached
IRVariable getInstructionVariable(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)
.getInstructionVariable(getInstructionTag(instruction))
exists(TranslatedElement element, InstructionTag tag |
element = getInstructionTranslatedElement(instruction) and
tag = getInstructionTag(instruction) and
(
result = element.getInstructionVariable(tag) or
result.(IRStringLiteral).getAST() = element.getInstructionStringLiteral(tag)
)
)
}
cached
@@ -265,12 +280,6 @@ private module Cached {
.getInstructionConstantValue(getInstructionTag(instruction))
}
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)
.getInstructionStringLiteral(getInstructionTag(instruction))
}
cached
CSharpType getInstructionExceptionType(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)

View File

@@ -22,6 +22,12 @@ abstract class IRVariable extends TIRVariable {
abstract string toString();
/**
* Holds if this variable's value cannot be changed within a function. Currently used for string
* literals, but could also apply to `const` global and static variables.
*/
predicate isReadOnly() { none() }
/**
* Gets the type of the variable.
*/
@@ -113,34 +119,43 @@ class IRStaticUserVariable extends IRUserVariable {
final override Language::StaticVariable getVariable() { result = var }
}
abstract class IRGeneratedVariable extends IRVariable {
Language::AST ast;
Language::LanguageType type;
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
override string toString() { result = getBaseString() + getLocationString() }
override string getUniqueId() { none() }
final string getLocationString() {
result = ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { none() }
}
IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) {
result.getAST() = ast and
result.getTag() = tag
}
class IRTempVariable extends IRVariable, IRAutomaticVariable, TIRTempVariable {
Language::AST ast;
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
TempVariableTag tag;
Language::LanguageType type;
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
final override Language::LanguageType getLanguageType() { result = type }
final override Language::AST getAST() { result = ast }
final override string getUniqueId() {
result = "Temp: " + Construction::getTempVariableUniqueId(this)
}
final TempVariableTag getTag() { result = tag }
override string toString() {
result = getBaseString() + ast.getLocation().getStartLine().toString() + ":" +
ast.getLocation().getStartColumn().toString()
}
string getBaseString() { result = "#temp" }
override string getBaseString() { result = "#temp" }
}
class IRReturnVariable extends IRTempVariable {
@@ -154,3 +169,19 @@ class IRThrowVariable extends IRTempVariable {
override string getBaseString() { result = "#throw" }
}
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
Language::StringLiteral literal;
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
final override predicate isReadOnly() { any() }
final override string getUniqueId() {
result = "String: " + getLocationString() + "=" + Language::getStringLiteralText(literal)
}
override string getBaseString() { result = "#string" }
final Language::StringLiteral getLiteral() { result = literal }
}

View File

@@ -818,14 +818,12 @@ class FloatConstantInstruction extends ConstantInstruction {
FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType }
}
class StringConstantInstruction extends Instruction {
Language::StringLiteral value;
class StringConstantInstruction extends VariableInstruction {
override IRStringLiteral var;
StringConstantInstruction() { value = Construction::getInstructionStringLiteral(this) }
final override string getImmediateString() { result = Language::getStringLiteralText(getValue()) }
final override string getImmediateString() { result = Language::getStringLiteralText(value) }
final Language::StringLiteral getValue() { result = value }
final Language::StringLiteral getValue() { result = var.getLiteral() }
}
class BinaryInstruction extends Instruction {

View File

@@ -341,11 +341,6 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::ConstantValueInstruction).getValue()
}
cached
Language::StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::StringConstantInstruction).getValue()
}
cached
Language::BuiltInOperation getInstructionBuiltInOperation(Instruction instruction) {
result = getOldInstruction(instruction)