[PATCH] Static analysis checker for catch handler inversion

Aaron Ballman aaron at aaronballman.com
Wed Jan 7 07:23:28 PST 2015


Ping

On Mon, Dec 15, 2014 at 9:57 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
> Ping
>
> On Thu, Dec 4, 2014 at 10:23 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
>> Ping
>>
>> On Tue, Nov 25, 2014 at 9:59 AM, Aaron Ballman <aaron at aaronballman.com> wrote:
>>> Ping
>>>
>>> On Mon, Nov 17, 2014 at 4:15 PM, Aaron Ballman <aaron at aaronballman.com> wrote:
>>>> On Fri, Nov 14, 2014 at 5:36 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>>>>> On Fri, Nov 14, 2014 at 7:55 AM, Aaron Ballman <aaron at aaronballman.com>
>>>>> wrote:
>>>>>>
>>>>>> On Thu, Nov 13, 2014 at 10:06 PM, Richard Smith <richard at metafoo.co.uk>
>>>>>> wrote:
>>>>>> > +    std::list<QualType> BaseClassTypes;
>>>>>> >
>>>>>> > This will allocate memory for every node; it would be better to use a
>>>>>> > SmallVector here (and use a depth-first search rather than a
>>>>>> > breadth-first
>>>>>> > one so you're only modifying one end of your list).
>>>>>> >
>>>>>> > +    for (auto &CurType : BaseClassTypes) {
>>>>>> >
>>>>>> > It's a bit scary to be iterating over your container while modifying it
>>>>>> > (even though it's actually correct in this case). Alternative idiom:
>>>>>> >
>>>>>> > SmallVector<QualType, 8> BaseClassTypes;
>>>>>> > BaseClassTypes.push_back(...);
>>>>>> > while (!BaseClassTypes.empty()) {
>>>>>> >   QualType T = BaseClassTypes.pop_back_val();
>>>>>> >   // ... maybe push back some values.
>>>>>> > }
>>>>>>
>>>>>> I have a strong preference for your idiom. ;-)
>>>>>>
>>>>>> >
>>>>>> > +      auto I = std::find_if(
>>>>>> > +          HandledTypes.begin(), HandledTypes.end(),
>>>>>> >
>>>>>> > This is still quadratic-time; maybe use a DenseMap with the canonical
>>>>>> > QualType plus a "was it a pointer" flag as a key?
>>>>>>
>>>>>> I've given this a shot in my latest patch. Thank you for the feedback!
>>>>>
>>>>>
>>>>>  +  unsigned IsReference : 1;
>>>>>
>>>>> I think we don't need / want an IsReference flag. Consider:
>>>>>
>>>>>   try { throw Derived(); }
>>>>>   catch (Base) {}
>>>>>   catch (Derived &d) {}
>>>>>
>>>>> The second catch handler is unreachable even though we have a by
>>>>> reference/by value mismatch.
>>>>
>>>> That's a very good point. Thanks! I've added an additional test for that case.
>>>>
>>>>>
>>>>>
>>>>> +      QualType Underlying = CurType.underlying();
>>>>> +      if (auto *RD = Underlying->getAsCXXRecordDecl()) {
>>>>> +        for (const auto &B : RD->bases())
>>>>> +          BaseClassTypes.push_back(QualTypeExt(B.getType(),
>>>>> CurType.isPointer(),
>>>>> +                                               CurType.isReference()));
>>>>>
>>>>> Per [except.handle]p1, you should only consider public, unambiguous base
>>>>> classes here. Rather than walk the base classes yourself, you could use
>>>>> CXXRecordDecl::lookupInBases to enumerate the base classes and paths, and
>>>>> then check the public unambiguous ones.
>>>>
>>>> I've made this change in the attached patch. Additionally, this patch
>>>> no longer pays attention to exception declarations that are invalid,
>>>> such as can be had from using auto in a catch clause.
>>>>
>>>> Thanks!
>>>>
>>>> ~Aaron



More information about the cfe-commits mailing list