mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
C++: HashCons for new, new[], sizeof, alignof
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
* Provides an implementation of Hash consing.
|
||||
* See https://en.wikipedia.org/wiki/Hash_consing
|
||||
*
|
||||
* The predicate `hashCons` converts an expression into a `HC`, which is an
|
||||
* The predicate `hashCons` converts an expression into a `HashCons`, which is an
|
||||
* abstract type presenting the hash-cons of the expression. If two
|
||||
* expressions have the same `HC` then they are structurally equal.
|
||||
* expressions have the same `HashCons` then they are structurally equal.
|
||||
*
|
||||
* Important note: this library ignores the possibility that the value of
|
||||
* an expression might change between one occurrence and the next. For
|
||||
@@ -92,18 +92,51 @@ private cached newtype HCBase =
|
||||
mk_MemberFunctionCall(trg, qual, args, _)
|
||||
}
|
||||
or
|
||||
HC_NewExpr(Type t, HC_Alloc alloc, HC_Init init) {
|
||||
mk_NewExpr(t, alloc, init, _, _)
|
||||
} or
|
||||
HC_NewArrayExpr(Type t, HC_Alloc alloc, HC_Init init) {
|
||||
mk_NewArrayExpr(t, alloc, init, _, _)
|
||||
}
|
||||
or
|
||||
HC_SizeofType(Type t) {mk_SizeofType(t, _)}
|
||||
or
|
||||
HC_SizeofExpr(HashCons child) {mk_SizeofExpr(child, _)}
|
||||
or
|
||||
HC_AlignofType(Type t) {mk_AlignofType(t, _)}
|
||||
or
|
||||
HC_AlignofExpr(HashCons child) {mk_AlignofExpr(child, _)}
|
||||
or
|
||||
// Any expression that is not handled by the cases above is
|
||||
// given a unique number based on the expression itself.
|
||||
HC_Unanalyzable(Expr e) { not analyzableExpr(e,_) }
|
||||
|
||||
/** Used to implement hash-consing of `new` placement argument lists */
|
||||
private newtype HC_Alloc =
|
||||
HC_EmptyAllocArgs(Function fcn) {
|
||||
exists(NewOrNewArrayExpr n |
|
||||
n.getAllocator() = fcn
|
||||
)
|
||||
}
|
||||
or HC_AllocArgCons(Function fcn, HashCons hc, int i, HC_Alloc list, boolean aligned) {
|
||||
mk_AllocArgCons(fcn, hc, i, list, aligned, _)
|
||||
}
|
||||
or
|
||||
HC_NoAlloc()
|
||||
private newtype HC_Init =
|
||||
HC_NoInit()
|
||||
or
|
||||
HC_HasInit(HashCons hc) {mk_HasInit(hc, _)}
|
||||
|
||||
/** Used to implement hash-consing of argument lists */
|
||||
private cached newtype HC_Args =
|
||||
private newtype HC_Args =
|
||||
HC_EmptyArgs(Function fcn) {
|
||||
any()
|
||||
}
|
||||
or HC_ArgCons(Function fcn, HashCons hc, int i, HC_Args list) {
|
||||
mk_ArgCons(fcn, hc, i, list, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* HashCons is the hash-cons of an expression. The relationship between `Expr`
|
||||
* and `HC` is many-to-one: every `Expr` has exactly one `HC`, but multiple
|
||||
@@ -127,8 +160,10 @@ class HashCons extends HCBase {
|
||||
/** Gets the kind of the HC. This can be useful for debugging. */
|
||||
string getKind() {
|
||||
if this instanceof HC_IntLiteral then result = "IntLiteral" else
|
||||
if this instanceof HC_EnumConstantAccess then result = "EnumConstantAccess" else
|
||||
if this instanceof HC_FloatLiteral then result = "FloatLiteral" else
|
||||
if this instanceof HC_StringLiteral then result = "StringLiteral" else
|
||||
if this instanceof HC_Nullptr then result = "Nullptr" else
|
||||
if this instanceof HC_Variable then result = "Variable" else
|
||||
if this instanceof HC_FieldAccess then result = "FieldAccess" else
|
||||
if this instanceof HC_Deref then result = "Deref" else
|
||||
@@ -140,6 +175,12 @@ class HashCons extends HCBase {
|
||||
if this instanceof HC_Unanalyzable then result = "Unanalyzable" else
|
||||
if this instanceof HC_NonmemberFunctionCall then result = "NonmemberFunctionCall" else
|
||||
if this instanceof HC_MemberFunctionCall then result = "MemberFunctionCall" else
|
||||
if this instanceof HC_NewExpr then result = "NewExpr" else
|
||||
if this instanceof HC_NewArrayExpr then result = "NewArrayExpr" else
|
||||
if this instanceof HC_SizeofType then result = "SizeofTypeOperator" else
|
||||
if this instanceof HC_SizeofExpr then result = "SizeofExprOperator" else
|
||||
if this instanceof HC_AlignofType then result = "AlignofTypeOperator" else
|
||||
if this instanceof HC_AlignofExpr then result = "AlignofExprOperator" else
|
||||
result = "error"
|
||||
}
|
||||
|
||||
@@ -446,6 +487,195 @@ private predicate mk_ArgCons(Function fcn, HashCons hc, int i, HC_Args list, Fun
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holds if `fc` is a call to `fcn`, `fc`'s first `i` arguments have hash-cons
|
||||
* `list`, and `fc`'s argument at index `i` has hash-cons `hc`.
|
||||
*/
|
||||
private predicate mk_AllocArgCons(Function fcn, HashCons hc, int i, HC_Alloc list, boolean aligned, FunctionCall fc) {
|
||||
analyzableFunctionCall(fc) and
|
||||
fc.getTarget() = fcn and
|
||||
hc = hashCons(fc.getArgument(i).getFullyConverted()) and
|
||||
(
|
||||
exists(HashCons head, HC_Alloc tail |
|
||||
list = HC_AllocArgCons(fcn, head, i - 1, tail, aligned) and
|
||||
mk_AllocArgCons(fcn, head, i - 1, tail, aligned, fc) and
|
||||
(
|
||||
aligned = true and
|
||||
i > 2
|
||||
or
|
||||
aligned = false and
|
||||
i > 1
|
||||
)
|
||||
)
|
||||
or
|
||||
(
|
||||
aligned = true and
|
||||
i = 2
|
||||
or
|
||||
aligned = false and
|
||||
i = 1
|
||||
) and
|
||||
list = HC_EmptyAllocArgs(fcn)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mk_HasInit(HashCons hc, NewOrNewArrayExpr new) {
|
||||
hc = hashCons(new.(NewExpr).getInitializer()) or
|
||||
hc = hashCons(new.(NewArrayExpr).getInitializer())
|
||||
}
|
||||
|
||||
private predicate analyzableNewExpr(NewExpr new) {
|
||||
strictcount(new.getAllocatedType()) = 1 and
|
||||
(
|
||||
not exists(new.getAllocatorCall())
|
||||
or
|
||||
strictcount(new.getAllocatorCall()) = 1
|
||||
) and (
|
||||
not exists(new.getInitializer())
|
||||
or
|
||||
strictcount(new.getInitializer()) = 1
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mk_NewExpr(Type t, HC_Alloc alloc, HC_Init init, boolean aligned, NewExpr new) {
|
||||
analyzableNewExpr(new) and
|
||||
t = new.getAllocatedType() and
|
||||
(
|
||||
new.hasAlignedAllocation() and
|
||||
aligned = true
|
||||
or
|
||||
not new.hasAlignedAllocation() and
|
||||
aligned = false
|
||||
)
|
||||
and
|
||||
(
|
||||
exists(FunctionCall fc, HashCons head, HC_Alloc tail |
|
||||
fc = new.getAllocatorCall() and
|
||||
alloc = HC_AllocArgCons(fc.getTarget(), head, fc.getNumberOfArguments() - 1, tail, aligned) and
|
||||
mk_AllocArgCons(fc.getTarget(), head, fc.getNumberOfArguments() - 1, tail, aligned, fc)
|
||||
)
|
||||
or
|
||||
exists(FunctionCall fc |
|
||||
fc = new.getAllocatorCall() and
|
||||
(
|
||||
aligned = true and
|
||||
fc.getNumberOfArguments() = 2
|
||||
or
|
||||
aligned = false and
|
||||
fc.getNumberOfArguments() = 1
|
||||
) and
|
||||
alloc = HC_EmptyAllocArgs(fc.getTarget())
|
||||
)
|
||||
or
|
||||
not exists(new.getAllocatorCall()) and
|
||||
alloc = HC_NoAlloc()
|
||||
)
|
||||
and
|
||||
(
|
||||
init = HC_HasInit(hashCons(new.getInitializer()))
|
||||
or
|
||||
not exists(new.getInitializer()) and
|
||||
init = HC_NoInit()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate analyzableNewArrayExpr(NewArrayExpr new) {
|
||||
strictcount(new.getAllocatedType().getUnspecifiedType()) = 1 and
|
||||
strictcount(new.getAllocatedType().getUnspecifiedType()) = 1 and
|
||||
(
|
||||
not exists(new.getAllocatorCall())
|
||||
or
|
||||
strictcount(new.getAllocatorCall().getFullyConverted()) = 1
|
||||
) and (
|
||||
not exists(new.getInitializer())
|
||||
or
|
||||
strictcount(new.getInitializer().getFullyConverted()) = 1
|
||||
)
|
||||
}
|
||||
|
||||
private predicate mk_NewArrayExpr(Type t, HC_Alloc alloc, HC_Init init, boolean aligned,
|
||||
NewArrayExpr new) {
|
||||
analyzableNewArrayExpr(new) and
|
||||
t = new.getAllocatedType() and
|
||||
(
|
||||
new.hasAlignedAllocation() and
|
||||
aligned = true
|
||||
or
|
||||
not new.hasAlignedAllocation() and
|
||||
aligned = false
|
||||
)
|
||||
and
|
||||
(
|
||||
exists(FunctionCall fc, HashCons head, HC_Alloc tail |
|
||||
fc = new.getAllocatorCall() and
|
||||
alloc = HC_AllocArgCons(fc.getTarget(), head, fc.getNumberOfArguments() - 1, tail, aligned) and
|
||||
mk_AllocArgCons(fc.getTarget(), head, fc.getNumberOfArguments() - 1, tail, aligned, fc)
|
||||
)
|
||||
or
|
||||
exists(FunctionCall fc |
|
||||
fc = new.getAllocatorCall() and
|
||||
(
|
||||
aligned = true and
|
||||
fc.getNumberOfArguments() = 2
|
||||
or
|
||||
aligned = false and
|
||||
fc.getNumberOfArguments() = 1
|
||||
) and
|
||||
alloc = HC_EmptyAllocArgs(fc.getTarget())
|
||||
)
|
||||
or
|
||||
not exists(new.getAllocatorCall()) and
|
||||
alloc = HC_NoAlloc()
|
||||
)
|
||||
and
|
||||
(
|
||||
init = HC_HasInit(hashCons(new.getInitializer()))
|
||||
or
|
||||
not exists(new.getInitializer()) and
|
||||
init = HC_NoInit()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate analyzableSizeofType(SizeofTypeOperator e) {
|
||||
strictcount(e.getType().getUnspecifiedType()) = 1 and
|
||||
strictcount(e.getTypeOperand()) = 1
|
||||
}
|
||||
|
||||
private predicate mk_SizeofType(Type t, SizeofTypeOperator e) {
|
||||
analyzableSizeofType(e) and
|
||||
t = e.getTypeOperand()
|
||||
}
|
||||
|
||||
private predicate analyzableSizeofExpr(Expr e) {
|
||||
e instanceof SizeofExprOperator and
|
||||
strictcount(e.getAChild().getFullyConverted()) = 1
|
||||
}
|
||||
|
||||
private predicate mk_SizeofExpr(HashCons child, SizeofExprOperator e) {
|
||||
analyzableSizeofExpr(e) and
|
||||
child = hashCons(e.getAChild())
|
||||
}
|
||||
|
||||
private predicate analyzableAlignofType(AlignofTypeOperator e) {
|
||||
strictcount(e.getType().getUnspecifiedType()) = 1 and
|
||||
strictcount(e.getTypeOperand()) = 1
|
||||
}
|
||||
|
||||
private predicate mk_AlignofType(Type t, AlignofTypeOperator e) {
|
||||
analyzableAlignofType(e) and
|
||||
t = e.getTypeOperand()
|
||||
}
|
||||
|
||||
private predicate analyzableAlignofExpr(AlignofExprOperator e) {
|
||||
strictcount(e.getExprOperand()) = 1
|
||||
}
|
||||
|
||||
private predicate mk_AlignofExpr(HashCons child, AlignofExprOperator e) {
|
||||
analyzableAlignofExpr(e) and
|
||||
child = hashCons(e.getAChild())
|
||||
}
|
||||
|
||||
/** Gets the hash-cons of expression `e`. */
|
||||
cached HashCons hashCons(Expr e) {
|
||||
exists (int val, Type t
|
||||
@@ -514,6 +744,36 @@ cached HashCons hashCons(Expr e) {
|
||||
result = HC_MemberFunctionCall(fcn, qual, args)
|
||||
)
|
||||
or
|
||||
exists(Type t, HC_Alloc alloc, HC_Init init, boolean aligned
|
||||
| mk_NewExpr(t, alloc, init, aligned, e) and
|
||||
result = HC_NewExpr(t, alloc, init)
|
||||
)
|
||||
or
|
||||
exists(Type t, HC_Alloc alloc, HC_Init init, boolean aligned
|
||||
| mk_NewArrayExpr(t, alloc, init, aligned, e) and
|
||||
result = HC_NewArrayExpr(t, alloc, init)
|
||||
)
|
||||
or
|
||||
exists(Type t
|
||||
| mk_SizeofType(t, e) and
|
||||
result = HC_SizeofType(t)
|
||||
)
|
||||
or
|
||||
exists(HashCons child
|
||||
| mk_SizeofExpr(child, e) and
|
||||
result = HC_SizeofExpr(child)
|
||||
)
|
||||
or
|
||||
exists(Type t
|
||||
| mk_AlignofType(t, e) and
|
||||
result = HC_AlignofType(t)
|
||||
)
|
||||
or
|
||||
exists(HashCons child
|
||||
| mk_AlignofExpr(child, e) and
|
||||
result = HC_AlignofExpr(child)
|
||||
)
|
||||
or
|
||||
(
|
||||
mk_Nullptr(e) and
|
||||
result = HC_Nullptr()
|
||||
@@ -545,5 +805,11 @@ predicate analyzableExpr(Expr e, string kind) {
|
||||
(analyzableArrayAccess(e) and kind = "ArrayAccess") or
|
||||
(analyzablePointerDereferenceExpr(e) and kind = "PointerDereferenceExpr") or
|
||||
(analyzableNonmemberFunctionCall(e) and kind = "NonmemberFunctionCall") or
|
||||
(analyzableMemberFunctionCall(e) and kind = "MemberFunctionCall")
|
||||
(analyzableMemberFunctionCall(e) and kind = "MemberFunctionCall") or
|
||||
(analyzableNewExpr(e) and kind = "NewExpr") or
|
||||
(analyzableNewArrayExpr(e) and kind = "NewArrayExpr") or
|
||||
(analyzableSizeofType(e) and kind = "SizeofTypeOperator") or
|
||||
(analyzableSizeofExpr(e) and kind = "SizeofExprOperator") or
|
||||
(analyzableAlignofType(e) and kind = "AlignofTypeOperator") or
|
||||
(analyzableAlignofExpr(e) and kind = "AlignofExprOperator")
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@
|
||||
| test.cpp:92:11:92:11 | x | 92:c11-c11 93:c10-c10 |
|
||||
| test.cpp:97:3:97:3 | x | 97:c3-c3 98:c3-c3 |
|
||||
| test.cpp:97:3:97:5 | ... ++ | 97:c3-c5 98:c3-c5 |
|
||||
| test.cpp:103:10:103:11 | 1 | 103:c10-c11 104:c7-c7 107:c7-c7 108:c7-c7 10:c16-c16 179:c21-c21 |
|
||||
| test.cpp:103:10:103:11 | 1 | 103:c10-c11 104:c7-c7 107:c7-c7 108:c7-c7 10:c16-c16 179:c21-c21 247:c11-c11 248:c11-c11 270:c19-c19 271:c19-c19 |
|
||||
| test.cpp:104:3:104:3 | x | 104:c3-c3 105:c3-c3 106:c3-c3 107:c3-c3 108:c3-c3 |
|
||||
| test.cpp:105:7:105:7 | 2 | 105:c7-c7 106:c7-c7 107:c11-c11 108:c11-c11 21:c16-c16 |
|
||||
| test.cpp:105:7:105:7 | 2 | 105:c7-c7 106:c7-c7 107:c11-c11 108:c11-c11 21:c16-c16 249:c11-c11 270:c15-c15 270:c22-c22 271:c15-c15 271:c22-c22 272:c15-c15 |
|
||||
| test.cpp:107:7:107:11 | ... + ... | 107:c7-c11 108:c7-c11 |
|
||||
| test.cpp:110:15:110:17 | 1 | 110:c15-c17 111:c9-c11 |
|
||||
| test.cpp:110:15:110:17 | (char *)... | 110:c15-c17 111:c9-c11 |
|
||||
@@ -73,3 +73,27 @@
|
||||
| test.cpp:179:17:179:17 | y | 179:c17-c17 179:c17-c17 |
|
||||
| test.cpp:179:17:179:21 | ... + ... | 179:c17-c21 179:c17-c21 |
|
||||
| test.cpp:185:17:185:17 | y | 185:c17-c17 185:c17-c17 |
|
||||
| test.cpp:202:3:202:18 | sizeof(padded_t) | 202:c3-c18 204:c3-c18 |
|
||||
| test.cpp:205:24:205:34 | sizeof(int) | 205:c24-c34 253:c25-c35 254:c25-c35 |
|
||||
| test.cpp:206:25:206:43 | alignof(int_holder) | 206:c25-c43 206:c3-c21 |
|
||||
| test.cpp:208:27:208:27 | x | 208:c27-c27 210:c10-c10 211:c11-c11 211:c24-c24 |
|
||||
| test.cpp:209:10:209:15 | holder | 209:c10-c15 209:c29-c34 |
|
||||
| test.cpp:209:10:209:18 | (...) | 209:c10-c18 209:c29-c37 |
|
||||
| test.cpp:209:17:209:17 | x | 209:c17-c17 209:c36-c36 |
|
||||
| test.cpp:209:22:209:37 | sizeof(<expr>) | 209:c22-c37 209:c3-c18 |
|
||||
| test.cpp:210:10:210:11 | (...) | 210:c10-c11 211:c11-c12 211:c24-c25 |
|
||||
| test.cpp:211:16:211:25 | alignof(<expr>) | 211:c16-c25 211:c3-c12 |
|
||||
| test.cpp:247:3:247:12 | new | 247:c3-c12 248:c3-c12 |
|
||||
| test.cpp:253:16:253:36 | new[] | 253:c16-c36 254:c16-c36 |
|
||||
| test.cpp:256:3:256:21 | new | 256:c3-c21 257:c3-c21 |
|
||||
| test.cpp:256:7:256:10 | (void *)... | 256:c7-c10 257:c7-c10 260:c11-c14 261:c11-c14 |
|
||||
| test.cpp:256:7:256:10 | ptr1 | 256:c7-c10 257:c7-c10 260:c11-c14 261:c11-c14 |
|
||||
| test.cpp:258:7:258:10 | (void *)... | 258:c7-c10 262:c11-c14 |
|
||||
| test.cpp:258:7:258:10 | ptr2 | 258:c7-c10 262:c11-c14 |
|
||||
| test.cpp:260:3:260:25 | new | 260:c3-c25 261:c3-c25 |
|
||||
| test.cpp:260:7:260:8 | 32 | 260:c7-c8 261:c7-c8 262:c7-c8 264:c7-c8 265:c7-c8 267:c7-c8 268:c7-c8 270:c7-c8 271:c7-c8 272:c7-c8 |
|
||||
| test.cpp:260:7:260:8 | (size_t)... | 260:c7-c8 261:c7-c8 262:c7-c8 264:c7-c8 265:c7-c8 267:c7-c8 268:c7-c8 270:c7-c8 271:c7-c8 272:c7-c8 |
|
||||
| test.cpp:264:3:264:19 | new | 264:c3-c19 265:c3-c19 |
|
||||
| test.cpp:267:3:267:23 | new[] | 267:c3-c23 268:c3-c23 |
|
||||
| test.cpp:267:21:267:22 | 10 | 267:c21-c22 268:c21-c22 92:c15-c16 |
|
||||
| test.cpp:272:19:272:19 | 3 | 272:c19-c19 35:c16-c16 |
|
||||
|
||||
@@ -184,3 +184,90 @@ int test13(int y) {
|
||||
int test14(int y) {
|
||||
return SQUARE(y);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
char y;
|
||||
} padded_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
} int_holder;
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
int test15(int x) {
|
||||
sizeof(padded_t);
|
||||
alignof(padded_t);
|
||||
sizeof(padded_t);
|
||||
sizeof(int_holder) + sizeof(int);
|
||||
alignof(int_holder) + alignof(int_holder);
|
||||
|
||||
int_holder holder = {x: x};
|
||||
sizeof(holder.x) + sizeof(holder.x);
|
||||
sizeof(x);
|
||||
alignof(x) + alignof(x);
|
||||
}
|
||||
|
||||
static void *operator new(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, size_t alignment, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, size_t alignment) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size, size_t alignment, void *placement) {
|
||||
return placement;
|
||||
}
|
||||
|
||||
static void *operator new[](size_t size, size_t alignment) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void test16() {
|
||||
new int(1);
|
||||
new int(1);
|
||||
new int(2);
|
||||
|
||||
int x;
|
||||
|
||||
char *ptr1 = new char[sizeof(int)];
|
||||
char *ptr2 = new char[sizeof(int)];
|
||||
|
||||
new(ptr1) IntHolder;
|
||||
new(ptr1) IntHolder;
|
||||
new(ptr2) IntHolder;
|
||||
|
||||
new(32, ptr1) IntHolder;
|
||||
new(32, ptr1) IntHolder;
|
||||
new(32, ptr2) IntHolder;
|
||||
|
||||
new(32) IntHolder;
|
||||
new(32) IntHolder;
|
||||
|
||||
new(32) IntHolder[10];
|
||||
new(32) IntHolder[10];
|
||||
|
||||
new(32) int[2] {1, 2};
|
||||
new(32) int[2] {1, 2};
|
||||
new(32) int[2] {3, 4};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user