Clang Static Analyzer

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Clang Static Analyzer

Tom Stellard via cfe-dev
Hello everyone,

I have some questions about the exploded graph.

class A {
public:
  A() {foo();}
  void foo();
};
int main() {
  A a;
}

When I use the clang to dump the exploded graph of the code above. There is only one exploded graph.

class A {
public:
  A() {foo();}
  void foo();
};
int main() {
  A *a = new A();
  delete a;
}

But when I dump the code above. There is two exploded graph, one for main and another for the construction of the class A.

My question is: what is the difference between using the pointer and using the object to initialize a class? Can I use the path-sensitive checker to explore the exploded graph of the construction.

Regards,
Xin

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Clang Static Analyzer

Tom Stellard via cfe-dev
It seems that in the first case the analyzer decides to inline the
constructor - i.e. jump into it and see what exactly is going on inside
it, and apply these operations within the current analysis. And then it
decides not to analyze the constructor separately, because it has a
better idea about this part of the program when it knows what's going on
around the code.

Normally we don't guarantee that we inline any particular function, just
try our best. In this case, it might be that the analyzer just wasn't
ever taught that operator-new calls *that* constructor; instead, he
decides to behave as if an unknown function is being called.

In fact, you can see and confirm all the details by looking at the
exploded graphs themselves; they should be quite easy to understand,
even though they often contain too much information.

On 6/19/17 7:05 PM, Xin Wang via cfe-dev wrote:

> Hello everyone,
>
> I have some questions about the exploded graph.
>
> /class A {
> public:
>   A() {foo();}
>   void foo();
> };
> int main() {
> /
> /  A a;
> /
> /}
> /
> When I use the clang to dump the exploded graph of the code above.
> There is only one exploded graph.
>
> /class A {
> public:
>   A() {foo();}
>   void foo();
> };
> int main() {
>   A *a = new A();
> /
> /  delete a;
> /
> /}
>
> /
> But when I dump the code above. There is two exploded graph, one for
> main and another for the construction of the class A.
>
> My question is: what is the difference between using the pointer and
> using the object to initialize a class? Can I use the path-sensitive
> checker to explore the exploded graph of the construction.
>
> Regards,
> Xin
>
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Clang Static Analyzer

Tom Stellard via cfe-dev
Thank you very much!

But I still have a question. I am writing a checker to check if a function is called during ctor/dtor.

void VirtualCallChecker::checkPreCall(const CallEvent &Call, 
                                                        CheckerContext &C) const {
  const Decl *D = dyn_cast_or_null<Decl>(Call.getDecl());
  if (!D)
    return;
  ProgramStateRef state = C.getState();
  // Enter a constructor, increase the corresponding integer
  if (dyn_cast<CXXConstructorDecl>(D)) {
    unsigned constructorflag = state->get<ConstructorFlag>();
    state = state->set<ConstructorFlag>(++constructorflag);
    C.addTransition(state);
    return;
  }
  if (state->get<ConstructorFlag>() > 0) {
    if (!BT_CT) {
      BT_CT.reset(new BugType(this, "Call to virtual function during construction", 
                  "not pure"));
    }
    ExplodedNode *N = C.generateNonFatalErrorNode();
    auto Reporter = llvm::make_unique<BugReport>(*BT_CT, BT_CT->getName(), N);
    C.emitReport(std::move(Reporter));
    return;
  }
}

If I use this checker to check the code which use the pointer to construct the class, it seems that the static analyzer doesn't enter the construction which is not inline. Is it true that the static analyzer doesn't enter the exploded graph which is not inline?

Regards,
Xin

2017-06-19 12:00 GMT-07:00 Artem Dergachev <[hidden email]>:
It seems that in the first case the analyzer decides to inline the constructor - i.e. jump into it and see what exactly is going on inside it, and apply these operations within the current analysis. And then it decides not to analyze the constructor separately, because it has a better idea about this part of the program when it knows what's going on around the code.

Normally we don't guarantee that we inline any particular function, just try our best. In this case, it might be that the analyzer just wasn't ever taught that operator-new calls *that* constructor; instead, he decides to behave as if an unknown function is being called.

In fact, you can see and confirm all the details by looking at the exploded graphs themselves; they should be quite easy to understand, even though they often contain too much information.

On 6/19/17 7:05 PM, Xin Wang via cfe-dev wrote:
Hello everyone,

I have some questions about the exploded graph.

/class A {
public:
  A() {foo();}
  void foo();
};
int main() {
/
/  A a;
/
/}
/
When I use the clang to dump the exploded graph of the code above. There is only one exploded graph.

/class A {
public:
  A() {foo();}
  void foo();
};
int main() {
  A *a = new A();
/
/  delete a;
/
/}

/
But when I dump the code above. There is two exploded graph, one for main and another for the construction of the class A.

My question is: what is the difference between using the pointer and using the object to initialize a class? Can I use the path-sensitive checker to explore the exploded graph of the construction.

Regards,
Xin


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Clang Static Analyzer

Tom Stellard via cfe-dev
If the function is inlined, then its exploded graph becomes part of the
big graph, with the necessary adjustments to the context.

If it is not inlined ("evaluated conservatively), then just one CallExpr
node is added to the graph instead; in this case the graph of the callee
function is not looked at (it may not even be available), and this node
behaves similarly for all functions: by destroying the data gathered by
the analyzer if this function call might have altered this data. In any
case there may be more nodes added by the checkers around the call.

20/06/2017 8:33 AM, Xin Wang wrote:

> Thank you very much!
>
> But I still have a question. I am writing a checker to check if a
> function is called during ctor/dtor.
>
>     void VirtualCallChecker::checkPreCall(const CallEvent &Call,
>     CheckerContext &C) const {
>       const Decl *D = dyn_cast_or_null<Decl>(Call.getDecl());
>       if (!D)
>         return;
>       ProgramStateRef state = C.getState();
>       // Enter a constructor, increase the corresponding integer
>       if (dyn_cast<CXXConstructorDecl>(D)) {
>         unsigned constructorflag = state->get<ConstructorFlag>();
>         state = state->set<ConstructorFlag>(++constructorflag);
>         C.addTransition(state);
>         return;
>       }
>       if (state->get<ConstructorFlag>() > 0) {
>         if (!BT_CT) {
>           BT_CT.reset(new BugType(this, "Call to virtual function
>     during construction",
>                       "not pure"));
>         }
>         ExplodedNode *N = C.generateNonFatalErrorNode();
>         auto Reporter = llvm::make_unique<BugReport>(*BT_CT,
>     BT_CT->getName(), N);
>         C.emitReport(std::move(Reporter));
>         return;
>       }
>     }
>
> If I use this checker to check the code which use the pointer to
> construct the class, it seems that the static analyzer doesn't enter
> the construction which is not inline. Is it true that the static
> analyzer doesn't enter the exploded graph which is not inline?
>
> Regards,
> Xin
>
> 2017-06-19 12:00 GMT-07:00 Artem Dergachev <[hidden email]
> <mailto:[hidden email]>>:
>
>     It seems that in the first case the analyzer decides to inline the
>     constructor - i.e. jump into it and see what exactly is going on
>     inside it, and apply these operations within the current analysis.
>     And then it decides not to analyze the constructor separately,
>     because it has a better idea about this part of the program when
>     it knows what's going on around the code.
>
>     Normally we don't guarantee that we inline any particular
>     function, just try our best. In this case, it might be that the
>     analyzer just wasn't ever taught that operator-new calls *that*
>     constructor; instead, he decides to behave as if an unknown
>     function is being called.
>
>     In fact, you can see and confirm all the details by looking at the
>     exploded graphs themselves; they should be quite easy to
>     understand, even though they often contain too much information.
>
>     On 6/19/17 7:05 PM, Xin Wang via cfe-dev wrote:
>
>         Hello everyone,
>
>         I have some questions about the exploded graph.
>
>         /class A {
>         public:
>           A() {foo();}
>           void foo();
>         };
>         int main() {
>         /
>         /  A a;
>         /
>         /}
>         /
>         When I use the clang to dump the exploded graph of the code
>         above. There is only one exploded graph.
>
>         /class A {
>         public:
>           A() {foo();}
>           void foo();
>         };
>         int main() {
>           A *a = new A();
>         /
>         /  delete a;
>         /
>         /}
>
>         /
>         But when I dump the code above. There is two exploded graph,
>         one for main and another for the construction of the class A.
>
>         My question is: what is the difference between using the
>         pointer and using the object to initialize a class? Can I use
>         the path-sensitive checker to explore the exploded graph of
>         the construction.
>
>         Regards,
>         Xin
>
>
>         _______________________________________________
>         cfe-dev mailing list
>         [hidden email] <mailto:[hidden email]>
>         http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>         <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev>
>
>
>

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Clang Static Analyzer

Tom Stellard via cfe-dev
Thanks for your help!

Regards,
Xin

2017-06-20 0:16 GMT-07:00 Artem Dergachev <[hidden email]>:
If the function is inlined, then its exploded graph becomes part of the big graph, with the necessary adjustments to the context.

If it is not inlined ("evaluated conservatively), then just one CallExpr node is added to the graph instead; in this case the graph of the callee function is not looked at (it may not even be available), and this node behaves similarly for all functions: by destroying the data gathered by the analyzer if this function call might have altered this data. In any case there may be more nodes added by the checkers around the call.


20/06/2017 8:33 AM, Xin Wang wrote:
Thank you very much!

But I still have a question. I am writing a checker to check if a function is called during ctor/dtor.

    void VirtualCallChecker::checkPreCall(const CallEvent &Call,
    CheckerContext &C) const {
      const Decl *D = dyn_cast_or_null<Decl>(Call.getDecl());
      if (!D)
        return;
      ProgramStateRef state = C.getState();
      // Enter a constructor, increase the corresponding integer
      if (dyn_cast<CXXConstructorDecl>(D)) {
        unsigned constructorflag = state->get<ConstructorFlag>();
        state = state->set<ConstructorFlag>(++constructorflag);
        C.addTransition(state);
        return;
      }
      if (state->get<ConstructorFlag>() > 0) {
        if (!BT_CT) {
          BT_CT.reset(new BugType(this, "Call to virtual function
    during construction",
                      "not pure"));
        }
        ExplodedNode *N = C.generateNonFatalErrorNode();
        auto Reporter = llvm::make_unique<BugReport>(*BT_CT,
    BT_CT->getName(), N);
        C.emitReport(std::move(Reporter));
        return;
      }
    }

If I use this checker to check the code which use the pointer to construct the class, it seems that the static analyzer doesn't enter the construction which is not inline. Is it true that the static analyzer doesn't enter the exploded graph which is not inline?

Regards,
Xin

2017-06-19 12:00 GMT-07:00 Artem Dergachev <[hidden email] <mailto:[hidden email]>>:


    It seems that in the first case the analyzer decides to inline the
    constructor - i.e. jump into it and see what exactly is going on
    inside it, and apply these operations within the current analysis.
    And then it decides not to analyze the constructor separately,
    because it has a better idea about this part of the program when
    it knows what's going on around the code.

    Normally we don't guarantee that we inline any particular
    function, just try our best. In this case, it might be that the
    analyzer just wasn't ever taught that operator-new calls *that*
    constructor; instead, he decides to behave as if an unknown
    function is being called.

    In fact, you can see and confirm all the details by looking at the
    exploded graphs themselves; they should be quite easy to
    understand, even though they often contain too much information.

    On 6/19/17 7:05 PM, Xin Wang via cfe-dev wrote:

        Hello everyone,

        I have some questions about the exploded graph.

        /class A {
        public:
          A() {foo();}
          void foo();
        };
        int main() {
        /
        /  A a;
        /
        /}
        /
        When I use the clang to dump the exploded graph of the code
        above. There is only one exploded graph.

        /class A {
        public:
          A() {foo();}
          void foo();
        };
        int main() {
          A *a = new A();
        /
        /  delete a;
        /
        /}

        /
        But when I dump the code above. There is two exploded graph,
        one for main and another for the construction of the class A.

        My question is: what is the difference between using the
        pointer and using the object to initialize a class? Can I use
        the path-sensitive checker to explore the exploded graph of
        the construction.

        Regards,
        Xin


        _______________________________________________
        cfe-dev mailing list
        [hidden email] <mailto:[hidden email]>
        http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
        <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev>






_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Loading...