[PATCH] D95307: [StaticAnalyzer] Add checking for degenerate base class in MemRegion

Deep Majumder via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 25 22:45:06 PST 2021


RedDocMD added a comment.

Thanks @NoQ for the tip on the right test command!
My own belief is that this patch is just a hack that squelches the problem, instead of solving it. I am limited by my own inexperience with the codebase and am trying to learn more to help better.

That said, couple of observations that I made while exploring the bug:

1. Referring to loop in line 1119 of `SimpleSValBuilder.cpp`.  This loop is necessary since we need to access the right sub-object. (The test at line 203 in `pointer-to-member.cpp` is a good demonstration why)
2. However,  when we have static casts on the pointer-to-member, this loop is also triggered.

The trouble is that the above two cases behave inconsistently with each other. Consider the following example for case 1:

  struct B {
    int f;
  };
  struct L1 : public B { };
  struct R1 : public B { };
  struct M : public L1, R1 { };
  struct L2 : public M { };
  struct R2 : public M { };
  struct D2 : public L2, R2 { };
  
  void diamond() {
    M m;
  
    static_cast<L1 *>(&m)->f = 7;
    static_cast<R1 *>(&m)->f = 16;
  
    int L1::* pl1 = &B::f;
    int M::* pm_via_l1 = pl1;
  
    int R1::* pr1 = &B::f;
    int M::* pm_via_r1 = pr1;
  
    (m.*(pm_via_l1) == 7); 
    (m.*(pm_via_r1) == 16);
  }

This behaves correctly. If we run `I->getType()->dump()` on each iteration of the loop, we get something like this:

  RecordType 0x55a70ad60d50 'struct L1'
  `-CXXRecord 0x55a70ad60cb8 'L1'
  RecordType 0x55a70ad60b20 'struct B'
  `-CXXRecord 0x55a70ad60a90 'B'
  2 levels of base specifiers
  RecordType 0x55a70ad60f50 'struct R1'
  `-CXXRecord 0x55a70ad60ec0 'R1'
  RecordType 0x55a70ad60b20 'struct B'
  `-CXXRecord 0x55a70ad60a90 'B'
  2 levels of base specifiers

Running the same analysis for the regressing code:

  struct Base {
    int field;
  };
  
  struct Derived : public Base {};
  
  void static_cast_test() {
    int Derived::* derived_field = &Derived::field;
    Base base;
    base.field = 5;
    int Base::* base_field = static_cast<int Base::*>(derived_field);
    (base.*base_field == 5);

we get the following dump;

  RecordType 0x55676ded06a0 'struct Base'
  `-CXXRecord 0x55676ded0610 'Base'
  RecordType 0x55676ded06a0 'struct Base'
  `-CXXRecord 0x55676ded0610 'Base'
  2 base specifier

Clearly, there is a bug elsewhere. The method `PointerToMember::begin()` returns an iterator to a list of `CXXBaseSpecifiers`, which according to the docs is for keeping track of `static_casts`. However, it seems that the base-specifier list is being used for something else. I am not sure in which function introduces this problem. Probably somewhere in the ASTVisitor for the StaticAnalyzer this problem is introduced. I will keep on digging and add more comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D95307/new/

https://reviews.llvm.org/D95307



More information about the cfe-commits mailing list