Exemple #1
0
int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
    if (LHS.getNameKind() != RHS.getNameKind())
        return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1);

    switch (LHS.getNameKind()) {
    case DeclarationName::Identifier: {
        IdentifierInfo *LII = LHS.getAsIdentifierInfo();
        IdentifierInfo *RII = RHS.getAsIdentifierInfo();
        if (!LII) return RII ? -1 : 0;
        if (!RII) return 1;

        return LII->getName().compare(RII->getName());
    }

    case DeclarationName::ObjCZeroArgSelector:
    case DeclarationName::ObjCOneArgSelector:
    case DeclarationName::ObjCMultiArgSelector: {
        Selector LHSSelector = LHS.getObjCSelector();
        Selector RHSSelector = RHS.getObjCSelector();
        unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
        for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
            switch (LHSSelector.getNameForSlot(I).compare(
                        RHSSelector.getNameForSlot(I))) {
            case -1:
                return true;
            case 1:
                return false;
            default:
                break;
            }
        }

        return compareInt(LN, RN);
    }

    case DeclarationName::CXXConstructorName:
    case DeclarationName::CXXDestructorName:
    case DeclarationName::CXXConversionFunctionName:
        if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()))
            return -1;
        if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
            return 1;
        return 0;

    case DeclarationName::CXXOperatorName:
        return compareInt(LHS.getCXXOverloadedOperator(),
                          RHS.getCXXOverloadedOperator());

    case DeclarationName::CXXLiteralOperatorName:
        return LHS.getCXXLiteralIdentifier()->getName().compare(
                   RHS.getCXXLiteralIdentifier()->getName());

    case DeclarationName::CXXUsingDirective:
        return 0;
    }

    return 0;
}
Exemple #2
0
DeclarationName::DeclarationName(Selector Sel) {
    if (!Sel.getAsOpaquePtr()) {
        Ptr = 0;
        return;
    }

    switch (Sel.getNumArgs()) {
    case 0:
        Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo());
        assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
        Ptr |= StoredObjCZeroArgSelector;
        break;

    case 1:
        Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo());
        assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo");
        Ptr |= StoredObjCOneArgSelector;
        break;

    default:
        Ptr = Sel.InfoPtr & ~Selector::ArgFlags;
        assert((Ptr & PtrMask) == 0 && "Improperly aligned MultiKeywordSelector");
        Ptr |= StoredDeclarationNameExtra;
        break;
    }
}
Exemple #3
0
bool operator<(DeclarationName LHS, DeclarationName RHS) {
  if (LHS.getNameKind() != RHS.getNameKind())
    return LHS.getNameKind() < RHS.getNameKind();
  
  switch (LHS.getNameKind()) {
  case DeclarationName::Identifier:
    return LHS.getAsIdentifierInfo()->getName() < 
                                         RHS.getAsIdentifierInfo()->getName();

  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector LHSSelector = LHS.getObjCSelector();
    Selector RHSSelector = RHS.getObjCSelector();
    for (unsigned I = 0, 
               N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs());
         I != N; ++I) {
      IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I);
      IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I);
      if (!LHSId || !RHSId)
        return LHSId && !RHSId;
        
      switch (LHSId->getName().compare(RHSId->getName())) {
      case -1: return true;
      case 1: return false;
      default: break;
      }
    }
    
    return LHSSelector.getNumArgs() < RHSSelector.getNumArgs();
  }
  
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
  case DeclarationName::CXXConversionFunctionName:
    return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType());
              
  case DeclarationName::CXXOperatorName:
    return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator();
              
  case DeclarationName::CXXUsingDirective:
    return false;
  }
              
  return false;
}
/// \brief Get the ASTContext-specific selector.
Selector GlobalSelector::getSelector(ASTContext &AST) const {
  if (isInvalid())
    return Selector();

  Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val));

  llvm::SmallVector<IdentifierInfo *, 8> Ids;
  for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs();
         i != e; ++i) {
    IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i);
    IdentifierInfo *II = &AST.Idents.get(GlobII->getName(),
                                       GlobII->getName() + GlobII->getLength());
    Ids.push_back(II);
  }

  return AST.Selectors.getSelector(GlobSel.getNumArgs(), Ids.data());
}
Exemple #5
0
void ODRHash::AddDeclarationName(DeclarationName Name) {
  // Index all DeclarationName and use index numbers to refer to them.
  auto Result = DeclNameMap.insert(std::make_pair(Name, DeclNameMap.size()));
  ID.AddInteger(Result.first->second);
  if (!Result.second) {
    // If found in map, the the DeclarationName has previously been processed.
    return;
  }

  // First time processing each DeclarationName, also process its details.
  AddBoolean(Name.isEmpty());
  if (Name.isEmpty())
    return;

  auto Kind = Name.getNameKind();
  ID.AddInteger(Kind);
  switch (Kind) {
  case DeclarationName::Identifier:
    AddIdentifierInfo(Name.getAsIdentifierInfo());
    break;
  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector S = Name.getObjCSelector();
    AddBoolean(S.isNull());
    AddBoolean(S.isKeywordSelector());
    AddBoolean(S.isUnarySelector());
    unsigned NumArgs = S.getNumArgs();
    for (unsigned i = 0; i < NumArgs; ++i) {
      AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
    }
    break;
  }
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXOperatorName:
    ID.AddInteger(Name.getCXXOverloadedOperator());
    break;
  case DeclarationName::CXXLiteralOperatorName:
    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
    break;
  case DeclarationName::CXXConversionFunctionName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXUsingDirective:
    break;
  case DeclarationName::CXXDeductionGuideName: {
    auto *Template = Name.getCXXDeductionGuideTemplate();
    AddBoolean(Template);
    if (Template) {
      AddDecl(Template);
    }
  }
  }
}
unsigned serialization::ComputeHash(Selector Sel) {
  unsigned N = Sel.getNumArgs();
  if (N == 0)
    ++N;
  unsigned R = 5381;
  for (unsigned I = 0; I != N; ++I)
    if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
      R = llvm::HashString(II->getName(), R);
  return R;
}
Exemple #7
0
bool ObjCMethodCall::argumentsMayEscape() const {
  if (isInSystemHeader() && !isInstanceMessage()) {
    Selector Sel = getSelector();
    if (Sel.getNumArgs() == 1 &&
        Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer"))
      return true;
  }

  return CallEvent::argumentsMayEscape();
}
/// \brief Get a GlobalSelector for the ASTContext-specific selector.
GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) {
  if (Sel.isNull())
    return GlobalSelector();

  ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);

  llvm::SmallVector<IdentifierInfo *, 8> Ids;
  for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs();
         i != e; ++i) {
    IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i);
    IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName(),
                                               II->getName() + II->getLength());
    Ids.push_back(GlobII);
  }

  Selector GlobSel = ProgImpl.getSelectors().getSelector(Sel.getNumArgs(),
                                                         Ids.data());
  return GlobalSelector(GlobSel.getAsOpaquePtr());
}
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
                                                   CheckerContext &C) const {
  // Check if the method is annotated with analyzer_noreturn.
  if (const ObjCMethodDecl *MD = Msg.getDecl()) {
    MD = MD->getCanonicalDecl();
    if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
      C.generateSink();
      return;
    }
  }

  // HACK: This entire check is to handle two messages in the Cocoa frameworks:
  // -[NSAssertionHandler
  //    handleFailureInMethod:object:file:lineNumber:description:]
  // -[NSAssertionHandler
  //    handleFailureInFunction:file:lineNumber:description:]
  // Eventually these should be annotated with __attribute__((noreturn)).
  // Because ObjC messages use dynamic dispatch, it is not generally safe to
  // assume certain methods can't return. In cases where it is definitely valid,
  // see if you can mark the methods noreturn or analyzer_noreturn instead of
  // adding more explicit checks to this method.

  if (!Msg.isInstanceMessage())
    return;

  const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
  if (!Receiver)
    return;
  if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
    return;

  Selector Sel = Msg.getSelector();
  switch (Sel.getNumArgs()) {
  default:
    return;
  case 4:
    lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
                            "handleFailureInFunction", "file", "lineNumber",
                            "description", nullptr);
    if (Sel != HandleFailureInFunctionSel)
      return;
    break;
  case 5:
    lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
                            "handleFailureInMethod", "object", "file",
                            "lineNumber", "description", nullptr);
    if (Sel != HandleFailureInMethodSel)
      return;
    break;
  }

  // If we got here, it's one of the messages we care about.
  C.generateSink();
}
void iOSAppSecLeakingWebCachesChecker::checkASTDecl(const ObjCMethodDecl *pMD, AnalysisManager &rMgr, BugReporter &rBR) const
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER (Method)" ) ;

  do
  {
    if ( !pMD )
    {
      break ;
    }
    
    Selector S = pMD ->getSelector() ;

    //There is no point of checking if you can't report it   
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG("redwud: ","Reporting will fail!" ) ;
      break ;
    }

    // connection:
    if ( S.getIdentifierInfoForSlot( 0 ) != m_piiConnection)
    {
      //MSEC_DEBUG("redwud: ","!connection: " << S.getAsString() ) ;
      break ;
    }

    ASTContext &Ctx = rBR.getContext() ; 

    // Two arguments
    if ( S.getNumArgs() != 2 )
    {
      break ;
    }
    
    // willCacheResponse:
    if ( S.getIdentifierInfoForSlot(1) != m_piiWillCacheResponse )
    {
      break ;
    }

    //Note: Intentionally made it common for both
    if ( !checkWillCacheResponse( pMD, Ctx ) )
    {
      break ;
    } 
    
    CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
      , m_szReportDesc, rBR, pMD ) ; 
      
  } while(_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT (Method)" ) ;
}
Exemple #11
0
void ODRHash::AddDeclarationName(DeclarationName Name) {
  AddBoolean(Name.isEmpty());
  if (Name.isEmpty())
    return;

  auto Kind = Name.getNameKind();
  ID.AddInteger(Kind);
  switch (Kind) {
  case DeclarationName::Identifier:
    AddIdentifierInfo(Name.getAsIdentifierInfo());
    break;
  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector S = Name.getObjCSelector();
    AddBoolean(S.isNull());
    AddBoolean(S.isKeywordSelector());
    AddBoolean(S.isUnarySelector());
    unsigned NumArgs = S.getNumArgs();
    for (unsigned i = 0; i < NumArgs; ++i) {
      AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
    }
    break;
  }
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXOperatorName:
    ID.AddInteger(Name.getCXXOverloadedOperator());
    break;
  case DeclarationName::CXXLiteralOperatorName:
    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
    break;
  case DeclarationName::CXXConversionFunctionName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXUsingDirective:
    break;
  case DeclarationName::CXXDeductionGuideName: {
    auto *Template = Name.getCXXDeductionGuideTemplate();
    AddBoolean(Template);
    if (Template) {
      AddDecl(Template);
    }
  }
  }
}
void NoReturnSubprogramChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
                                                   CheckerContext &C) const {
  // HACK: This entire check is to handle two messages in the Cocoa frameworks:
  // -[NSAssertionHandler
  //    handleFailureInMethod:object:file:lineNumber:description:]
  // -[NSAssertionHandler
  //    handleFailureInSubprogram:file:lineNumber:description:]
  // Eventually these should be annotated with __attribute__((noreturn)).
  // Because ObjC messages use dynamic dispatch, it is not generally safe to
  // assume certain methods can't return. In cases where it is definitely valid,
  // see if you can mark the methods noreturn or analyzer_noreturn instead of
  // adding more explicit checks to this method.

  if (!Msg.isInstanceMessage())
    return;

  const ObjCInterfaceDecl *Receiver = Msg.getReceiverInterface();
  if (!Receiver)
    return;
  if (!Receiver->getIdentifier()->isStr("NSAssertionHandler"))
    return;

  Selector Sel = Msg.getSelector();
  switch (Sel.getNumArgs()) {
  default:
    return;
  case 4:
    if (!isMultiArgSelector(&Sel, "handleFailureInSubprogram", "file",
                            "lineNumber", "description", NULL))
      return;
    break;
  case 5:
    if (!isMultiArgSelector(&Sel, "handleFailureInMethod", "object", "file",
                            "lineNumber", "description", NULL))
      return;
    break;
  }

  // If we got here, it's one of the messages we care about.
  C.generateSink();
}
Exemple #13
0
bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
                                     Selector Sel, ObjCMethodDecl *Method,
                                     bool isClassMessage,
                                     SourceLocation lbrac, SourceLocation rbrac,
                                     QualType &ReturnType, ExprValueKind &VK) {
  if (!Method) {
    // Apply default argument promotion as for (C99 6.5.2.2p6).
    for (unsigned i = 0; i != NumArgs; i++) {
      if (Args[i]->isTypeDependent())
        continue;

      DefaultArgumentPromotion(Args[i]);
    }

    unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found :
                                       diag::warn_inst_method_not_found;
    Diag(lbrac, DiagID)
      << Sel << isClassMessage << SourceRange(lbrac, rbrac);
    ReturnType = Context.getObjCIdType();
    VK = VK_RValue;
    return false;
  }

  ReturnType = Method->getSendResultType();
  VK = Expr::getValueKindForType(Method->getResultType());

  unsigned NumNamedArgs = Sel.getNumArgs();
  // Method might have more arguments than selector indicates. This is due
  // to addition of c-style arguments in method.
  if (Method->param_size() > Sel.getNumArgs())
    NumNamedArgs = Method->param_size();
  // FIXME. This need be cleaned up.
  if (NumArgs < NumNamedArgs) {
    Diag(lbrac, diag::err_typecheck_call_too_few_args)
      << 2 << NumNamedArgs << NumArgs;
    return false;
  }

  bool IsError = false;
  for (unsigned i = 0; i < NumNamedArgs; i++) {
    // We can't do any type-checking on a type-dependent argument.
    if (Args[i]->isTypeDependent())
      continue;

    Expr *argExpr = Args[i];

    ParmVarDecl *Param = Method->param_begin()[i];
    assert(argExpr && "CheckMessageArgumentTypes(): missing expression");

    if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
                            Param->getType(),
                            PDiag(diag::err_call_incomplete_argument)
                              << argExpr->getSourceRange()))
      return true;

    InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
                                                                      Param);
    ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr));
    if (ArgE.isInvalid())
      IsError = true;
    else
      Args[i] = ArgE.takeAs<Expr>();
  }

  // Promote additional arguments to variadic methods.
  if (Method->isVariadic()) {
    for (unsigned i = NumNamedArgs; i < NumArgs; ++i) {
      if (Args[i]->isTypeDependent())
        continue;

      IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0);
    }
  } else {
    // Check for extra arguments to non-variadic methods.
    if (NumArgs != NumNamedArgs) {
      Diag(Args[NumNamedArgs]->getLocStart(),
           diag::err_typecheck_call_too_many_args)
        << 2 /*method*/ << NumNamedArgs << NumArgs
        << Method->getSourceRange()
        << SourceRange(Args[NumNamedArgs]->getLocStart(),
                       Args[NumArgs-1]->getLocEnd());
    }
  }

  DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs);
  return IsError;
}
void iOSAppSecAbusingURLSchemesChecker::checkASTDecl(const ObjCMethodDecl *pMD, AnalysisManager &rMgr, BugReporter &rBR) const
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER (Method)" ) ;

  do
  {
    if ( !pMD )
    {
      break ;
    }
    
    Selector S = pMD ->getSelector() ;

    //There is no point of checking if you can't report it   
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG("redwud: ","Reporting will fail!" ) ;
      break ;
    }

    // application:
    if ( S.getIdentifierInfoForSlot( 0 ) != m_piiApplication )
    {
      //MSEC_DEBUG("redwud: ","!application: " << S.getAsString() ) ;
      break ;
    }

    unsigned iArgs = S.getNumArgs() ;
    ASTContext &Ctx = rBR.getContext() ; 

    //
    //openURL:
    //

    do
    {
      if ( iArgs != 4 )
      {
        break ;
      }
      
      if ( (S.getIdentifierInfoForSlot(1) != m_piiOpenURL) 
           || (S.getIdentifierInfoForSlot(2) != m_piiSourceApplication)
           || (S.getIdentifierInfoForSlot(3) != m_piiAnnotation ) )
      {
        break ;
      }
          
      if ( !checkOpenURL( pMD, Ctx ) )
      {
        break ;
      } 
      
      CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
        , m_szReportDesc 
        , rBR, pMD ) ; 
    
    } while(_PASSING_) ;

    //
    //handleOpenURL:
    //

    do
    {
      if ( iArgs != 2 )
      {
        break ;
      }
      
      if ( S.getIdentifierInfoForSlot(1) != m_piiHandleOpenURL )
      {
        break ;
      }
      
      //Note: Intentionally made it common for both
      if ( !checkOpenURL( pMD, Ctx ) )
      {
        break ;
      } 
      
      CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
        , m_szReportDesc, rBR, pMD ) ;
    
    } while(_PASSING_) ; //handleOpenURL:
  
  } while(_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT (Method)" ) ;
}
//FIXME: Consider other methods than setObject like dictionaryWithObjectsAndKeys
/// Process call to NSMutableArray:setObject:forKey: 
void iOSAppSecInsecureKeyChainStorageChecker::checkPreObjCMessage 
  (const ObjCMethodCall &M, CheckerContext &C) const
{
  MSEC_DEBUG_FUNC("redwud:","ENTER") ;

  do
  {
    const ObjCInterfaceDecl *pRxInterface = M.getReceiverInterface() ;
    
    if ( !pRxInterface )
    {
      break ;
    }

    ASTContext &Ctx = C.getASTContext() ;
    Selector selCurr = M.getSelector() ; 

    initIdentifierInfo( Ctx ) ;

    //TODO: Check this with property, this might not work on it    
    //NSMutableDictionary 
    if ( pRxInterface ->getIdentifier() != m_piiNSMutableDictionary )
    {
      break ;
    } 

    //setObject 
    IdentifierInfo *piiSetObject = selCurr.getIdentifierInfoForSlot(0) ;  

    if ( piiSetObject != m_piiSetObject )
    {
       break ;
    }
    
    //forKey
    IdentifierInfo *piiForKey = selCurr.getIdentifierInfoForSlot(1) ;

    if ( piiForKey != m_piiForKey )
    {
       break ;
    }
    
    // MSEC_DEBUG("redwud: ", "'" << selCurr.getAsString() << "' num args: " << selCurr.getNumArgs() ) ;
    if ( selCurr.getNumArgs() != 2 )
    {
      // Unlikely to be of concerned 
      break ;
    }

    ProgramStateRef pProgState = C.getState() ;
    const LocationContext *pLCtx = C.getLocationContext() ; 

    //Get the value for "aKey" parameter (2nd)
    // Checking this first because checking the first parameter takes a bit longer    
    const Expr *pKeyExpr = M.getArgExpr(1) ;
    SVal argValKey = pProgState ->getSVal( pKeyExpr, pLCtx ) ;

    if ( !CMSecCommon::isSValContains( argValKey, "kSecAttrAccessible" ) )
    {
      // Not of concern
      break ; 
    }

    //Get the value for "anObject" parameter (1st)
    const Expr *pObjExpr = M.getArgExpr(0) ;
    SVal argValAnObject = pProgState ->getSVal( pObjExpr, pLCtx ) ;

    //Get receiver as symbol, should be used in either condition
    SymbolRef pSymQuery = M.getReceiverSVal().getAsSymbol() ;

    if ( !pSymQuery )
    {
      // redwud: Can't save empty receiver symbol,
      // so there is no point of moving on, 
      // there must be something wrong with this
      break ;
    }

    //Idea: if [query] is currently being tracked change it to different status, e.g. secure
    //      if not tracked add new secure state

    bool bInsecureObject = isInsecureObject( argValAnObject ) ; 

    pProgState = pProgState ->set <StreamMap>( pSymQuery, bInsecureObject ? 
      KeyChainState::getNotSecure() : KeyChainState::getSecure() ) ;   

    // Add transition of state
    //redwud: it seems that the states are transitioned at some point
    C.addTransition( pProgState ) ;

    MSEC_DEBUG( "redwud: ", "Finish checking!" ) ; 
  } while (_PASSING_) ;


  MSEC_DEBUG_FUNC("redwud:","EXIT") ;
}