Static Checker: getting svals for a struct field value

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Static Checker: getting svals for a struct field value

Renato Golin via cfe-dev

I am new to building Clang static checkers and need some help.  I am implementing a PreCall callback function that checks calls to a certain family of functions (from a local library) that takes a struct as an argument.  I see how to get the SVal and Expr for the argument using CallEvent::getArgSVal() and CallEvent::getArgExpr().  What I’m struggling with is how to go from the SVal for the struct to an SVal for one of its fields.  In particular, how do I get the memory region associated with the struct value?  Once I have that, I think I know how to go from there, e.g.:

 

RecordType *structTy = structReg->getValueType()->getAsStructureType();

assert(structTy && “Value is not a structure”);

RecordDecl *structRD = structTy ->getDecl()->getDefinition();

assert(structRD && “structure has no definition”);

for (const auto *F : structRD->fields()) {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    if (FR->getDec()->getName() == “fieldName”)

        size = StoreMgr.getBinding(store, loc::MemRegionVal(FR));

}

 

But how do I get the memory region structReg?  And how do I get the Store store?

 

Thanks!


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

Re: Static Checker: getting svals for a struct field value

Renato Golin via cfe-dev
Hello Raymond,

1. You can get the Store with ProgramState::getStore() method().
2. To process an SVal representing a region, you may use SVal::getAsRegion() method. But I'm not sure what you really need here, could you explain more detailedly?
3. Your approach for FieldRegion will work, but it is better to search for a FieldDecl in your RecordDecl first and only then get its FieldRegion. FieldDecl has getName() method allowing doing this, so your code will look like:

for (const auto *F : structRD->fields()) {
  if (F->getName == "fieldName") {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    size = State->getSVal(FR);

}
}


where State is of ProgramStateRef type.


09.05.2016 21:55, McDowell, Raymond C. via cfe-dev пишет:

I am new to building Clang static checkers and need some help.  I am implementing a PreCall callback function that checks calls to a certain family of functions (from a local library) that takes a struct as an argument.  I see how to get the SVal and Expr for the argument using CallEvent::getArgSVal() and CallEvent::getArgExpr().  What I’m struggling with is how to go from the SVal for the struct to an SVal for one of its fields.  In particular, how do I get the memory region associated with the struct value?  Once I have that, I think I know how to go from there, e.g.:

 

RecordType *structTy = structReg->getValueType()->getAsStructureType();

assert(structTy && “Value is not a structure”);

RecordDecl *structRD = structTy ->getDecl()->getDefinition();

assert(structRD && “structure has no definition”);

for (const auto *F : structRD->fields()) {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    if (FR->getDec()->getName() == “fieldName”)

        size = StoreMgr.getBinding(store, loc::MemRegionVal(FR));

}

 

But how do I get the memory region structReg?  And how do I get the Store store?

 

Thanks!



_______________________________________________
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
|

Re: Static Checker: getting svals for a struct field value

Renato Golin via cfe-dev

Thanks, Alexey, for your help.

 

Here’s a more detailed explanation of what I’m trying to do.  In our project we’ve created a struct type containing a pointer to a buffer and the size of the buffer (in bytes), so that we can pass these around together and not lose track of the buffer size.  I’m trying to write a checker that will make sure that any buffer access is in bounds by checking that 0 <= offset and offset + chunk_size < buffer_size, where chunk_size is the size of the data being read from / written to the buffer.

 

Your suggestions have helped a lot, but I’m still stuck getting from the Buffer (struct) SVal to its RecordType.  You said to use SVal::getAsRegion() method to get the MemRegion.  The next step would seem to be using the getValueType() and getAsStructureType() methods, but first I need to convert the MemRegion to a VarRegion or a TypedValueRegion.  I tried each of these (using MemRegion::getAs), but both resulted in the checker crashing.

 

 

From: Alexey Sidorin [mailto:[hidden email]]
Sent: Monday, May 09, 2016 5:16 PM
To: McDowell, Raymond C.; [hidden email]
Subject: Re: [cfe-dev] Static Checker: getting svals for a struct field value

 

Hello Raymond,

1. You can get the Store with ProgramState::getStore() method().
2. To process an SVal representing a region, you may use SVal::getAsRegion() method. But I'm not sure what you really need here, could you explain more detailedly?
3. Your approach for FieldRegion will work, but it is better to search for a FieldDecl in your RecordDecl first and only then get its FieldRegion. FieldDecl has getName() method allowing doing this, so your code will look like:

for (const auto *F : structRD->fields()) {
  if (F->getName == "fieldName") {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    size = State->getSVal(FR);

}
}


where State is of ProgramStateRef type.


09.05.2016 21:55, McDowell, Raymond C. via cfe-dev пишет:

I am new to building Clang static checkers and need some help.  I am implementing a PreCall callback function that checks calls to a certain family of functions (from a local library) that takes a struct as an argument.  I see how to get the SVal and Expr for the argument using CallEvent::getArgSVal() and CallEvent::getArgExpr().  What I’m struggling with is how to go from the SVal for the struct to an SVal for one of its fields.  In particular, how do I get the memory region associated with the struct value?  Once I have that, I think I know how to go from there, e.g.:

 

RecordType *structTy = structReg->getValueType()->getAsStructureType();

assert(structTy && “Value is not a structure”);

RecordDecl *structRD = structTy ->getDecl()->getDefinition();

assert(structRD && “structure has no definition”);

for (const auto *F : structRD->fields()) {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    if (FR->getDec()->getName() == “fieldName”)

        size = StoreMgr.getBinding(store, loc::MemRegionVal(FR));

}

 

But how do I get the memory region structReg?  And how do I get the Store store?

 

Thanks!




_______________________________________________
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
|

Re: Static Checker: getting svals for a struct field value

Renato Golin via cfe-dev
In reply to this post by Renato Golin via cfe-dev

To follow up on my own question, in case others have it later… Here’s what I did, that seems to be working:

 

  SVal BuffBase, BuffSize;

  MemRegionManager &MRMgr = St->getStateManager().getRegionManager();

  const TypedValueRegion *BuffReg = Buff.castAs<nonloc::LazyCompoundVal>().getCVData()->getRegion();

  const RecordType *BuffRTy = BuffReg->getValueType()->getAsStructureType();

  assert(BuffRTy && "Input buffer value is not a structure");

  const RecordDecl *BuffRD = BuffRTy->getDecl()->getDefinition();

  assert(BuffRD && "Input buffer structure has no definition");

  for (const auto *F : BuffRD->fields()) {

    if (F->getName() == "base") {

      BuffBase = St->getSVal(MRMgr.getFieldRegion(F, BuffReg));

   }

    else if (F->getName() == "size") {

      BuffSize = St->getSVal(MRMgr.getFieldRegion(F, BuffReg));

    }

  }

 

The above code sets BuffBase and BuffSize to be SVals for the field values in the structure SVal Buff.  To assign values to the fields (instead of reading their current values), I used code like the following:

 

  const VarRegion *BuffReg = Buff.getAsRegion()->getAs<VarRegion>();

  const RecordType *BuffRTy = BuffReg->getValueType()->getAsStructureType();

  assert(BuffRTy && "Output buffer value is not a structure");

  const RecordDecl *BuffRD = BuffRTy->getDecl()->getDefinition();

  assert(BuffRD && "Output buffer structure has no definition");

  for (const auto *F : BuffRD->fields()) {

    if (F->getName() == "size") {

      const FieldRegion *SizeFR = St->getStateManager().getRegionManager().getFieldRegion(F, BuffReg);

      St = St->bindLoc(loc::MemRegionVal(SizeFR), Size);

    }

  }

 

This changes the size field to have the value Size.

 

 

From: McDowell, Raymond C.
Sent: Friday, May 13, 2016 1:14 PM
To: 'Alexey Sidorin'; [hidden email]
Subject: RE: [cfe-dev] Static Checker: getting svals for a struct field value

 

Thanks, Alexey, for your help.

 

Here’s a more detailed explanation of what I’m trying to do.  In our project we’ve created a struct type containing a pointer to a buffer and the size of the buffer (in bytes), so that we can pass these around together and not lose track of the buffer size.  I’m trying to write a checker that will make sure that any buffer access is in bounds by checking that 0 <= offset and offset + chunk_size < buffer_size, where chunk_size is the size of the data being read from / written to the buffer.

 

Your suggestions have helped a lot, but I’m still stuck getting from the Buffer (struct) SVal to its RecordType.  You said to use SVal::getAsRegion() method to get the MemRegion.  The next step would seem to be using the getValueType() and getAsStructureType() methods, but first I need to convert the MemRegion to a VarRegion or a TypedValueRegion.  I tried each of these (using MemRegion::getAs), but both resulted in the checker crashing.

 

 

From: Alexey Sidorin [[hidden email]]
Sent: Monday, May 09, 2016 5:16 PM
To: McDowell, Raymond C.; [hidden email]
Subject: Re: [cfe-dev] Static Checker: getting svals for a struct field value

 

Hello Raymond,

1. You can get the Store with ProgramState::getStore() method().
2. To process an SVal representing a region, you may use SVal::getAsRegion() method. But I'm not sure what you really need here, could you explain more detailedly?
3. Your approach for FieldRegion will work, but it is better to search for a FieldDecl in your RecordDecl first and only then get its FieldRegion. FieldDecl has getName() method allowing doing this, so your code will look like:

for (const auto *F : structRD->fields()) {
  if (F->getName == "fieldName") {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    size = State->getSVal(FR);

}
}


where State is of ProgramStateRef type.


09.05.2016 21:55, McDowell, Raymond C. via cfe-dev пишет:

I am new to building Clang static checkers and need some help.  I am implementing a PreCall callback function that checks calls to a certain family of functions (from a local library) that takes a struct as an argument.  I see how to get the SVal and Expr for the argument using CallEvent::getArgSVal() and CallEvent::getArgExpr().  What I’m struggling with is how to go from the SVal for the struct to an SVal for one of its fields.  In particular, how do I get the memory region associated with the struct value?  Once I have that, I think I know how to go from there, e.g.:

 

RecordType *structTy = structReg->getValueType()->getAsStructureType();

assert(structTy && “Value is not a structure”);

RecordDecl *structRD = structTy ->getDecl()->getDefinition();

assert(structRD && “structure has no definition”);

for (const auto *F : structRD->fields()) {

    FieldRegion *FR = MRMgr.getFieldRegion(F, structReg);

    if (FR->getDec()->getName() == “fieldName”)

        size = StoreMgr.getBinding(store, loc::MemRegionVal(FR));

}

 

But how do I get the memory region structReg?  And how do I get the Store store?

 

Thanks!



_______________________________________________
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
|

Re: Static Checker: getting svals for a struct field value

Renato Golin via cfe-dev
Hello,

I think there might be a subtle issue with your approach.

As far as I understand, 'Buff' is a lazy compound value. As such, it
represents an r-value of some structure, which is a result of a deep
copy of an object that was residing in 'BuffReg' (aka
getCVData()->getRegion()) at the moment of copying. Contents of
'BuffReg' might have changed since the copy was obtained. And 'Buff'
itself might have been written into a different region, or maybe into
multiple different regions - after all, that's the whole point of
copying objects. And in your code, you probably cannot obtain the
"current" region for the lazy compound value, from which it was
immediately read; even if you can, that's not the way to go.

If you're sure contents of the region have not changed since copy, then
there's no problem. However, say, consider the following code:

   struct S { int x; ... };
   S bar();
   void baz(S);

   int foo() {
     S s1 = bar();
     // s1: LazyCompoundVal for CXXTempObjectRegion for bar() expression;

     S s2 = s1;
     // s1: LazyCompoundVal for CXXTempObjectRegion for bar() expression;
     // s2: LazyCompoundVal for CXXTempObjectRegion for bar() expression;

     s1.x = 42;
     // s1: LazyCompoundVal for VarRegion s2;
     // s2: LazyCompoundVal for CXXTempObjectRegion for bar() expression;

     // s2 doesn't contain 42, but you're likely to read it through your
approach.
     baz(s2);
   }

If you're interested in contents of the LazyCompoundVal, rather than in
current contents of its origin-region, you should be working with the
second item in the CVData() - the Store thing. Store is a snapshot of
the whole memory at the moment of copying (due to magic, such copies are
very quick to obtain and lightweight to store, so it's a performance
optimization in the analyzer, in a sense).

So the suggestion is to replace St->getSVal(MRMgr.getFieldRegion(F,
BuffReg)) with something like
St->getStateManager().getStoreManager().getBinding(Buff.castAs<nonloc::LazyCompoundVal>().getCVData()->getStore(),
loc::MemRegionVal(MRMgr.getFieldRegion(F, BuffReg)), F->getType()). It
should do the trick.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Static Checker: getting svals for a struct field value

Renato Golin via cfe-dev
In reply to this post by Renato Golin via cfe-dev

Thanks, Artem!

 

My approach worked fine until I tried analyzing code that accessed the buffer in a return statement.  In that situation, for some reason I do not understand, the values of the buffer fields would disappear from the store.  However, your approach still works then.


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