@@ -153,12 +153,38 @@ predicate exprMayThrow(Expr e) {
153153 )
154154}
155155
156+ class NoThrowType extends Struct {
157+ NoThrowType ( ) { this .hasGlobalOrStdOrBslName ( "nothrow_t" ) }
158+ }
159+
156160/** An allocator that might throw an exception. */
157161class ThrowingAllocator extends Function {
158162 ThrowingAllocator ( ) {
159163 exists ( NewOrNewArrayExpr newExpr |
160164 newExpr .getAllocator ( ) = this and
161- functionMayThrow ( this )
165+ // Exclude custom overloads of `operator new`.
166+ // What we really want here is to only include the functions that satisfy `functionMayThrow`, but
167+ // there seems to be examples where `throw()` isn't extracted (which causes false positives).
168+ //
169+ // As noted in the QLDoc for `Function.getAllocatorCall`:
170+ //
171+ // "As a rule of thumb, there will be an allocator call precisely when the type
172+ // being allocated has a custom `operator new`, or when an argument list appears
173+ // after the `new` keyword and before the name of the type being allocated.
174+ //
175+ // In particular note that uses of placement-new and nothrow-new will have an
176+ // allocator call."
177+ //
178+ // So we say an allocator might throw if:
179+ // 1. It doesn't have a body
180+ // 2. there is a parameter that is not `nothrow`
181+ // 3. the allocator isn't marked with `throw()` or `noexcept`.
182+ not exists ( this .getBlock ( ) ) and
183+ exists ( Parameter p | p = this .getAParameter ( ) |
184+ not p .getUnspecifiedType ( ) instanceof NoThrowType
185+ ) and
186+ not this .isNoExcept ( ) and
187+ not this .isNoThrow ( )
162188 )
163189 }
164190}
0 commit comments