C++: Handle pointer decay and inferred array sizes

For function parameters that are subject to "pointer decay", the database contains the type as originally declared (e.g. `T[]` instead of `T*`). The IR needs the actual type. Similarly, for variable declared as an array of unknown size, the actual size needs to be inferred from the initializer (e.g. `char a[] = "blah";` needs to have the type `char[5]`).

I've opened a ticket to have the extractor emit the actual type alongside the declared type, but for now, this workaround is enough to unblock progress for typical code.
This commit is contained in:
Dave Bartolomeo
2019-02-12 12:41:05 -08:00
parent 6ab0eaac7d
commit aff2ea3316
9 changed files with 115 additions and 9 deletions

View File

@@ -2,6 +2,7 @@ private import internal.IRInternal
import FunctionIR
import cpp
import semmle.code.cpp.ir.implementation.TempVariableTag
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.internal.TempVariableTag
private import semmle.code.cpp.ir.internal.TIRVariable
@@ -70,7 +71,7 @@ abstract class IRUserVariable extends IRVariable {
}
override final Type getType() {
result = var.getType().getUnspecifiedType()
result = getVariableType(var)
}
override final Locatable getAST() {

View File

@@ -2,6 +2,7 @@ private import internal.IRInternal
import FunctionIR
import cpp
import semmle.code.cpp.ir.implementation.TempVariableTag
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.internal.TempVariableTag
private import semmle.code.cpp.ir.internal.TIRVariable
@@ -70,7 +71,7 @@ abstract class IRUserVariable extends IRVariable {
}
override final Type getType() {
result = var.getType().getUnspecifiedType()
result = getVariableType(var)
}
override final Locatable getAST() {

View File

@@ -1,5 +1,6 @@
import cpp
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.internal.OperandTag
private import InstructionTag
private import TranslatedElement
@@ -104,14 +105,14 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
(
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = getVariable().getType().getUnspecifiedType() and
resultType = getVariableType(getVariable()) and
isGLValue = true
) or
(
hasUninitializedInstruction() and
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = getVariable().getType().getUnspecifiedType() and
resultType = getVariableType(getVariable()) and
isGLValue = false
)
}
@@ -161,7 +162,7 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
}
override Type getTargetType() {
result = getVariable().getType().getUnspecifiedType()
result = getVariableType(getVariable())
}
private TranslatedInitialization getInitialization() {

View File

@@ -1,6 +1,7 @@
import cpp
import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.internal.OperandTag
private import semmle.code.cpp.ir.internal.TempVariableTag
private import InstructionTag
@@ -377,13 +378,13 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
(
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = param.getType().getUnspecifiedType() and
resultType = getVariableType(param) and
isGLValue = true
) or
(
tag = InitializerStoreTag() and
opcode instanceof Opcode::InitializeParameter and
resultType = param.getType().getUnspecifiedType() and
resultType = getVariableType(param) and
isGLValue = false
)
}

View File

@@ -2,6 +2,7 @@ private import internal.IRInternal
import FunctionIR
import cpp
import semmle.code.cpp.ir.implementation.TempVariableTag
private import semmle.code.cpp.ir.internal.IRUtilities
private import semmle.code.cpp.ir.internal.TempVariableTag
private import semmle.code.cpp.ir.internal.TIRVariable
@@ -70,7 +71,7 @@ abstract class IRUserVariable extends IRVariable {
}
override final Type getType() {
result = var.getType().getUnspecifiedType()
result = getVariableType(var)
}
override final Locatable getAST() {

View File

@@ -0,0 +1,34 @@
import cpp
/**
* Given a type, get the type that would result by applying "pointer decay".
* A function type becomes a pointer to that function type, and an array type
* becomes a pointer to the element type of the array. If the specified type
* is not subject to pointer decay, this predicate does not hold.
*/
private Type getDecayedType(Type type) {
result.(FunctionPointerType).getBaseType() = type.(RoutineType) or
result.(PointerType).getBaseType() = type.(ArrayType).getBaseType()
}
/**
* Get the actual type of the specified variable, as opposed to the declared type.
* This returns the type of the variable after any pointer decay is applied, and
* after any unsized array type has its size inferred from the initializer.
*/
Type getVariableType(Variable v) {
exists(Type declaredType |
declaredType = v.getType().getUnspecifiedType() and
if v instanceof Parameter then (
result = getDecayedType(declaredType) or
not exists(getDecayedType(declaredType)) and result = declaredType
)
else if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize() then (
result = v.getInitializer().getExpr().getType().getUnspecifiedType() or
not exists(v.getInitializer()) and result = declaredType
)
else (
result = declaredType
)
)
}