Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aff2ea3

Browse files
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.
1 parent 6ab0eaa commit aff2ea3

9 files changed

Lines changed: 115 additions & 9 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ private import internal.IRInternal
22
import FunctionIR
33
import cpp
44
import semmle.code.cpp.ir.implementation.TempVariableTag
5+
private import semmle.code.cpp.ir.internal.IRUtilities
56
private import semmle.code.cpp.ir.internal.TempVariableTag
67
private import semmle.code.cpp.ir.internal.TIRVariable
78

@@ -70,7 +71,7 @@ abstract class IRUserVariable extends IRVariable {
7071
}
7172

7273
override final Type getType() {
73-
result = var.getType().getUnspecifiedType()
74+
result = getVariableType(var)
7475
}
7576

7677
override final Locatable getAST() {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ private import internal.IRInternal
22
import FunctionIR
33
import cpp
44
import semmle.code.cpp.ir.implementation.TempVariableTag
5+
private import semmle.code.cpp.ir.internal.IRUtilities
56
private import semmle.code.cpp.ir.internal.TempVariableTag
67
private import semmle.code.cpp.ir.internal.TIRVariable
78

@@ -70,7 +71,7 @@ abstract class IRUserVariable extends IRVariable {
7071
}
7172

7273
override final Type getType() {
73-
result = var.getType().getUnspecifiedType()
74+
result = getVariableType(var)
7475
}
7576

7677
override final Locatable getAST() {

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedDeclarationEntry.qll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import cpp
22
private import semmle.code.cpp.ir.implementation.Opcode
3+
private import semmle.code.cpp.ir.internal.IRUtilities
34
private import semmle.code.cpp.ir.internal.OperandTag
45
private import InstructionTag
56
private import TranslatedElement
@@ -104,14 +105,14 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
104105
(
105106
tag = InitializerVariableAddressTag() and
106107
opcode instanceof Opcode::VariableAddress and
107-
resultType = getVariable().getType().getUnspecifiedType() and
108+
resultType = getVariableType(getVariable()) and
108109
isGLValue = true
109110
) or
110111
(
111112
hasUninitializedInstruction() and
112113
tag = InitializerStoreTag() and
113114
opcode instanceof Opcode::Uninitialized and
114-
resultType = getVariable().getType().getUnspecifiedType() and
115+
resultType = getVariableType(getVariable()) and
115116
isGLValue = false
116117
)
117118
}
@@ -161,7 +162,7 @@ abstract class TranslatedVariableDeclaration extends TranslatedElement, Initiali
161162
}
162163

163164
override Type getTargetType() {
164-
result = getVariable().getType().getUnspecifiedType()
165+
result = getVariableType(getVariable())
165166
}
166167

167168
private TranslatedInitialization getInitialization() {

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cpp
22
import semmle.code.cpp.ir.implementation.raw.IR
33
private import semmle.code.cpp.ir.implementation.Opcode
4+
private import semmle.code.cpp.ir.internal.IRUtilities
45
private import semmle.code.cpp.ir.internal.OperandTag
56
private import semmle.code.cpp.ir.internal.TempVariableTag
67
private import InstructionTag
@@ -377,13 +378,13 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
377378
(
378379
tag = InitializerVariableAddressTag() and
379380
opcode instanceof Opcode::VariableAddress and
380-
resultType = param.getType().getUnspecifiedType() and
381+
resultType = getVariableType(param) and
381382
isGLValue = true
382383
) or
383384
(
384385
tag = InitializerStoreTag() and
385386
opcode instanceof Opcode::InitializeParameter and
386-
resultType = param.getType().getUnspecifiedType() and
387+
resultType = getVariableType(param) and
387388
isGLValue = false
388389
)
389390
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ private import internal.IRInternal
22
import FunctionIR
33
import cpp
44
import semmle.code.cpp.ir.implementation.TempVariableTag
5+
private import semmle.code.cpp.ir.internal.IRUtilities
56
private import semmle.code.cpp.ir.internal.TempVariableTag
67
private import semmle.code.cpp.ir.internal.TIRVariable
78

@@ -70,7 +71,7 @@ abstract class IRUserVariable extends IRVariable {
7071
}
7172

7273
override final Type getType() {
73-
result = var.getType().getUnspecifiedType()
74+
result = getVariableType(var)
7475
}
7576

7677
override final Locatable getAST() {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import cpp
2+
3+
/**
4+
* Given a type, get the type that would result by applying "pointer decay".
5+
* A function type becomes a pointer to that function type, and an array type
6+
* becomes a pointer to the element type of the array. If the specified type
7+
* is not subject to pointer decay, this predicate does not hold.
8+
*/
9+
private Type getDecayedType(Type type) {
10+
result.(FunctionPointerType).getBaseType() = type.(RoutineType) or
11+
result.(PointerType).getBaseType() = type.(ArrayType).getBaseType()
12+
}
13+
14+
/**
15+
* Get the actual type of the specified variable, as opposed to the declared type.
16+
* This returns the type of the variable after any pointer decay is applied, and
17+
* after any unsized array type has its size inferred from the initializer.
18+
*/
19+
Type getVariableType(Variable v) {
20+
exists(Type declaredType |
21+
declaredType = v.getType().getUnspecifiedType() and
22+
if v instanceof Parameter then (
23+
result = getDecayedType(declaredType) or
24+
not exists(getDecayedType(declaredType)) and result = declaredType
25+
)
26+
else if declaredType instanceof ArrayType and not declaredType.(ArrayType).hasArraySize() then (
27+
result = v.getInitializer().getExpr().getType().getUnspecifiedType() or
28+
not exists(v.getInitializer()) and result = declaredType
29+
)
30+
else (
31+
result = declaredType
32+
)
33+
)
34+
}

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6591,3 +6591,39 @@ ir.cpp:
65916591
# 983| ValueCategory = prvalue(load)
65926592
# 983| 1: { ... }
65936593
# 985| 3: return ...
6594+
# 987| int PointerDecay(int[], int(float))
6595+
# 987| params:
6596+
# 987| 0: a
6597+
# 987| Type = int[]
6598+
# 987| 1: fn
6599+
# 987| Type = ..()(..)
6600+
# 987| body: { ... }
6601+
# 988| 0: return ...
6602+
# 988| 0: ... + ...
6603+
# 988| Type = int
6604+
# 988| ValueCategory = prvalue
6605+
# 988| 0: access to array
6606+
# 988| Type = int
6607+
# 988| ValueCategory = prvalue(load)
6608+
# 988| 0: a
6609+
# 988| Type = int *
6610+
# 988| ValueCategory = prvalue(load)
6611+
# 988| 1: 0
6612+
# 988| Type = int
6613+
# 988| Value = 0
6614+
# 988| ValueCategory = prvalue
6615+
# 988| 1: call to expression
6616+
# 988| Type = int
6617+
# 988| ValueCategory = prvalue
6618+
# 988| 0: fn
6619+
# 988| Type = ..(*)(..)
6620+
# 988| ValueCategory = prvalue(load)
6621+
# 988| 1: (float)...
6622+
# 988| Conversion = floating point conversion
6623+
# 988| Type = float
6624+
# 988| Value = 1.0
6625+
# 988| ValueCategory = prvalue
6626+
# 988| expr: 1.0
6627+
# 988| Type = double
6628+
# 988| Value = 1.0
6629+
# 988| ValueCategory = prvalue

cpp/ql/test/library-tests/ir/ir/ir.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,10 @@ void WhileStmtWithDeclaration(int x, int y) {
984984
}
985985
}
986986

987+
int PointerDecay(int a[], int fn(float)) {
988+
return a[0] + fn(1.0);
989+
}
990+
987991
#if 0
988992
void OperatorDelete() {
989993
delete static_cast<int*>(nullptr); // No destructor

cpp/ql/test/library-tests/ir/ir/raw_ir.expected

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2579,7 +2579,7 @@ ir.cpp:
25792579
# 573| r0_12(glval<char[4]>) = StringConstant["foo"] :
25802580
# 573| r0_13(char[4]) = Load : r0_12, mu0_2
25812581
# 573| mu0_14(char[4]) = Store : r0_11, r0_13
2582-
# 574| r0_15(glval<char[]>) = VariableAddress[a_infer] :
2582+
# 574| r0_15(glval<char[5]>) = VariableAddress[a_infer] :
25832583
# 574| r0_16(glval<char[5]>) = StringConstant["blah"] :
25842584
# 574| r0_17(char[5]) = Load : r0_16, mu0_2
25852585
# 574| mu0_18(char[5]) = Store : r0_15, r0_17
@@ -4339,3 +4339,30 @@ ir.cpp:
43394339
# 979| v7_9(void) = ConditionalBranch : r7_8
43404340
#-----| False -> Block 2
43414341
#-----| True -> Block 1
4342+
4343+
# 987| int PointerDecay(int[], int(float))
4344+
# 987| Block 0
4345+
# 987| v0_0(void) = EnterFunction :
4346+
# 987| mu0_1(unknown) = AliasedDefinition :
4347+
# 987| mu0_2(unknown) = UnmodeledDefinition :
4348+
# 987| r0_3(glval<int *>) = VariableAddress[a] :
4349+
# 987| mu0_4(int *) = InitializeParameter[a] : r0_3
4350+
# 987| r0_5(glval<..(*)(..)>) = VariableAddress[fn] :
4351+
# 987| mu0_6(..(*)(..)) = InitializeParameter[fn] : r0_5
4352+
# 988| r0_7(glval<int>) = VariableAddress[#return] :
4353+
# 988| r0_8(glval<int *>) = VariableAddress[a] :
4354+
# 988| r0_9(int *) = Load : r0_8, mu0_2
4355+
# 988| r0_10(int) = Constant[0] :
4356+
# 988| r0_11(int *) = PointerAdd[4] : r0_9, r0_10
4357+
# 988| r0_12(int) = Load : r0_11, mu0_2
4358+
# 988| r0_13(glval<..(*)(..)>) = VariableAddress[fn] :
4359+
# 988| r0_14(..(*)(..)) = Load : r0_13, mu0_2
4360+
# 988| r0_15(float) = Constant[1.0] :
4361+
# 988| r0_16(int) = Call : r0_14, r0_15
4362+
# 988| mu0_17(unknown) = ^CallSideEffect : mu0_2
4363+
# 988| r0_18(int) = Add : r0_12, r0_16
4364+
# 988| mu0_19(int) = Store : r0_7, r0_18
4365+
# 987| r0_20(glval<int>) = VariableAddress[#return] :
4366+
# 987| v0_21(void) = ReturnValue : r0_20, mu0_2
4367+
# 987| v0_22(void) = UnmodeledUse : mu*
4368+
# 987| v0_23(void) = ExitFunction :

0 commit comments

Comments
 (0)