C++: Exclude custom operator new allocators from the ThrowingAllocator class.

This commit is contained in:
Mathias Vorreiter Pedersen
2021-05-27 11:23:11 +02:00
parent e01d7127e2
commit 71a860a356

View File

@@ -153,12 +153,38 @@ predicate exprMayThrow(Expr e) {
)
}
class NoThrowType extends Struct {
NoThrowType() { this.hasGlobalOrStdOrBslName("nothrow_t") }
}
/** An allocator that might throw an exception. */
class ThrowingAllocator extends Function {
ThrowingAllocator() {
exists(NewOrNewArrayExpr newExpr |
newExpr.getAllocator() = this and
functionMayThrow(this)
// Exclude custom overloads of `operator new`.
// What we really want here is to only include the functions that satisfy `functionMayThrow`, but
// there seems to be examples where `throw()` isn't extracted (which causes false positives).
//
// As noted in the QLDoc for `Function.getAllocatorCall`:
//
// "As a rule of thumb, there will be an allocator call precisely when the type
// being allocated has a custom `operator new`, or when an argument list appears
// after the `new` keyword and before the name of the type being allocated.
//
// In particular note that uses of placement-new and nothrow-new will have an
// allocator call."
//
// So we say an allocator might throw if:
// 1. It doesn't have a body
// 2. there is a parameter that is not `nothrow`
// 3. the allocator isn't marked with `throw()` or `noexcept`.
not exists(this.getBlock()) and
exists(Parameter p | p = this.getAParameter() |
not p.getUnspecifiedType() instanceof NoThrowType
) and
not this.isNoExcept() and
not this.isNoThrow()
)
}
}