Hello. I am newbie in Clang Static Analyzer and I am trying to write new Clang Static Analyzer check, which is aimed to find issues with casting values to enum: if we cast anything which is no presented in target enum it will be unspecified/undefined behavior(depends on C++ version).

So my plan is:

  1. Find all casts in source code. Seems like ‘check::PreStmt>’ it’s what I need.
  2. In my implementation of checkPreStmt method I must get target type from CastExpr, but I don’t know, how to do it - can you help with it?
  3. Then if target type in Cast is Enum, I must get all values from this Enum and compare it with all possible values which can be presented by CastExpr->getSubExpr() - here I don’t know how to evaluate CastExpr->getSubExpr() and how to get all values from Enum.

Do you have any ideas?


Your overall plan sounds good, and i believe that such checker will be very useful, i'd love to have such check in the analyzer. If you want to post it upstream, i encourage you to start early by publishing prototypes on Phabricator for code reviews, even when you think they're not ready, just because code reviews are cool!

Path-sensitive analysis is indeed useful here because sometimes it's not immediately obvious from the code which values are possible for the sub-expression. Defining the buggy state can be a bit annoying because enum values can be non-contiguous and/or numerous; the former means that you'll potentially need to make a lot of State->assume(...) calls and see if none of the states with assumptions are null; the latter means that you'll need to make sure you identify segments of values to avoid calling assume() for *every* enum item. I also recommend ConstraintManager::assumeInclusiveRange() for direct assumptions over segments.

Your questions so far are AST questions, not specific to the analyzer. First of all, notice that every expression has a (qualified) type, which is the type of the value it evaluates to, and it can always be obtained via Expr::getType(). It may be void (eg., call expression for a function that returns void), but it's always there.

For cast-expression, as you might have already guessed, the type of the expression is the target type of the cast. Because, well, that's the whole point of the cast. This takes care of question 2.

Most functions return not raw Types but QualType objects that are types with qualifiers. You can always use the overloaded operator->() on the QualType to access the underlying Type; there's also QualType::getTypePtr(), but if you think you need it - most likely you don't.

Now, types, like statements or declarations, are a hierarchy. Some types are integer types, some are array or structure types, some are enum types. Enum types are represented by the EnumType class, to which you can try to dyn_cast<>() your type. Or, even better, use Type::getAs<>(), which can be accessed directly with operator->() on QualType.

If dyn_cast<>()/getAs<>() is successful - your type is an enum and you have a pointer to an EnumType object, so you can call EnumType::getDecl() to find the *declaration* of the enum in the code.

Also if the enum hides under a typedef, then the type wouldn't be an EnumType but it'd be a TypedefType, so the cast would fail. The easy way to get rid of typedefs is to do QualType::getCanonicalType().

Some declarations are forward declarations. You might need to do EnumDecl::getDefinition() to find the actual definition. Maybe you don't need that: i don't remember what operations are allowed on incomplete enum types.

Once you have your EnumDecl that is the definition, you can iterate over EnumDecl::enumerators() to see what values are present.

In Clang there are a lot more cast kinds of expressions than you probably expect, so you might want to take a look at the list of casts in clang/AST/OperationKinds.def and see which ones do you need; i don't think it'll be important at first, but just in case.

In order to quickly catch up on the basics, i also recommend the AST tutorial by Manuel Klimek at The Clang AST - a Tutorial - YouTube


Do you have something in mind like this: https://reviews.llvm.org/D33672 ?


Artem Dergachev via cfe-dev <cfe-dev@lists.llvm.org> ezt írta (időpont: 2018. okt. 25., Cs 4:32):

Didn’t know that this check is already implemented. I think I can continue this work (seems like original author of the change don’t work on it now). What do you think?

Given the lack of recent activity feel free to commandeer the revision. I think it should be quite close to be merged.

Ah, my memory of a surgeonfish never fails me.
Yeah, i guess just take it over.