Exemplo n.º 1
0
void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  initIdentifierInfo(C.getASTContext());

  if (!Call.isGlobalCFunction())
    return;

  if (Call.getCalleeIdentifier() != IIfclose)
    return;

  if (Call.getNumArgs() != 1)
    return;

  // Get the symbolic value corresponding to the file handle.
  SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol();
  if (!FileDesc)
    return;

  // Check if the stream has already been closed.
  ProgramStateRef State = C.getState();
  const StreamState *SS = State->get<StreamMap>(FileDesc);
  if (SS && SS->isClosed()) {
    reportDoubleClose(FileDesc, Call, C);
    return;
  }

  // Generate the next transition, in which the stream is closed.
  State = State->set<StreamMap>(FileDesc, StreamState::getClosed());
  C.addTransition(State);
}
Exemplo n.º 2
0
void MPIChecker::checkDoubleNonblocking(const CallEvent &PreCallEvent,
                                        CheckerContext &Ctx) const {
  if (!FuncClassifier->isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
    return;
  }
  const MemRegion *const MR =
      PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
  if (!MR)
    return;
  const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);

  // The region must be typed, in order to reason about it.
  if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
    return;

  ProgramStateRef State = Ctx.getState();
  const Request *const Req = State->get<RequestMap>(MR);

  // double nonblocking detected
  if (Req && Req->CurrentState == Request::State::Nonblocking) {
    ExplodedNode *ErrorNode = Ctx.generateNonFatalErrorNode();
    BReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ErrorNode,
                                      Ctx.getBugReporter());
    Ctx.addTransition(ErrorNode->getState(), ErrorNode);
  }
  // no error
  else {
    State = State->set<RequestMap>(MR, Request::State::Nonblocking);
    Ctx.addTransition(State);
  }
}
void DoubleFetchChecker::checkPostCall(const CallEvent &Call,CheckerContext &Ctx) const {
	const IdentifierInfo *ID = Call.getCalleeIdentifier();
	std::cout<<"[checkPostCall]------call function:"<<ID->getName().str()<<std::endl;

	ProgramStateRef state = Ctx.getState();
	if(ID == NULL) {
		return;
	}

	if (ID->getName() == "malloc") {
		SVal arg = Call.getArgSVal(0);
		SVal ret = Call.getReturnValue();
		if (this->isTaintedByTime(state, arg)){
			std::cout<<"[checkPostCall] arg of malloc is tainted."<<"\targ is:"<<toStr(arg)<<std::endl;
			//pass current taint tag to return value
			ProgramStateRef newstate = passTaints(state, arg, ret);
			if (newstate!=state && newstate != NULL){
				Ctx.addTransition(newstate);
				std::cout<<"[checkPostCall][add ret Taint finish] ret is "<<toStr(ret)<<std::endl;
				showValTaintTags(newstate, ret);
			}
			else
				std::cout<<"[checkPostCall][add ret Taint failed] ret is "<<toStr(ret)<<std::endl;
		}

		else{
			std::cout<<"[checkPostCall] arg of malloc not tainted."<<"\targ is:"<<toStr(arg)<<std::endl;
		}
	}


}
Exemplo n.º 4
0
void DoubleFetchChecker::checkPreCall(const CallEvent &Call,CheckerContext &Ctx) const {
	const IdentifierInfo *ID = Call.getCalleeIdentifier();
	ProgramStateRef state = Ctx.getState();
	if (ID == NULL) {
		return;
	}
	std::cout<<"\n";
	std::cout<<"[checkPreCall]-----call function:"<<ID->getName().str()<<std::endl;

}
void BlockInCriticalSectionChecker::reportBlockInCritSection(
    SymbolRef BlockDescSym, const CallEvent &Call, CheckerContext &C) const {
  ExplodedNode *ErrNode = C.generateNonFatalErrorNode();
  if (!ErrNode)
    return;

  std::string msg;
  llvm::raw_string_ostream os(msg);
  os << "Call to blocking function '" << Call.getCalleeIdentifier()->getName()
     << "' inside of critical section";
  auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
  R->addRange(Call.getSourceRange());
  R->markInteresting(BlockDescSym);
  C.emitReport(std::move(R));
}
Exemplo n.º 6
0
/// If we are in -dealloc or -dealloc is on the stack, handle the call if it is
/// call to Block_release().
void ObjCDeallocChecker::checkPreCall(const CallEvent &Call,
                                      CheckerContext &C) const {
  const IdentifierInfo *II = Call.getCalleeIdentifier();
  if (II != Block_releaseII)
    return;

  if (Call.getNumArgs() != 1)
    return;

  SymbolRef ReleasedValue = Call.getArgSVal(0).getAsSymbol();
  if (!ReleasedValue)
    return;

  transitionToReleaseValue(C, ReleasedValue);
}
Exemplo n.º 7
0
void MPIChecker::allRegionsUsedByWait(
    llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
    const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const {

  MemRegionManager *const RegionManager = MR->getMemRegionManager();

  if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) {
    const MemRegion *SuperRegion{nullptr};
    if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
      SuperRegion = ER->getSuperRegion();
    }

    // A single request is passed to MPI_Waitall.
    if (!SuperRegion) {
      ReqRegions.push_back(MR);
      return;
    }

    const auto &Size = Ctx.getStoreManager().getSizeInElements(
        Ctx.getState(), SuperRegion,
        CE.getArgExpr(1)->getType()->getPointeeType());
    const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue();

    for (size_t i = 0; i < ArrSize; ++i) {
      const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);

      const ElementRegion *const ER = RegionManager->getElementRegion(
          CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
          Ctx.getASTContext());

      ReqRegions.push_back(ER->getAs<MemRegion>());
    }
  } else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) {
    ReqRegions.push_back(MR);
  }
}
void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
        CheckerContext &C) const {
    ProgramStateRef state = C.getState();
    bool BuildSinks = false;

    if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
        BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();

    const Expr *Callee = CE.getOriginExpr();
    if (!BuildSinks && Callee)
        BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();

    if (!BuildSinks && CE.isGlobalCFunction()) {
        if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
            // HACK: Some functions are not marked noreturn, and don't return.
            //  Here are a few hardwired ones.  If this takes too long, we can
            //  potentially cache these results.
            BuildSinks
                = llvm::StringSwitch<bool>(StringRef(II->getName()))
                  .Case("exit", true)
                  .Case("panic", true)
                  .Case("error", true)
                  .Case("Assert", true)
                  // FIXME: This is just a wrapper around throwing an exception.
                  //  Eventually inter-procedural analysis should handle this easily.
                  .Case("ziperr", true)
                  .Case("assfail", true)
                  .Case("db_error", true)
                  .Case("__assert", true)
                  // For the purpose of static analysis, we do not care that
                  //  this MSVC function will return if the user decides to continue.
                  .Case("_wassert", true)
                  .Case("__assert_rtn", true)
                  .Case("__assert_fail", true)
                  .Case("dtrace_assfail", true)
                  .Case("yy_fatal_error", true)
                  .Case("_XCAssertionFailureHandler", true)
                  .Case("_DTAssertionFailureHandler", true)
                  .Case("_TSAssertionFailureHandler", true)
                  .Default(false);
        }
    }

    if (BuildSinks)
        C.generateSink();
}
Exemplo n.º 9
0
void MPIChecker::checkUnmatchedWaits(const CallEvent &PreCallEvent,
                                     CheckerContext &Ctx) const {
  if (!FuncClassifier->isWaitType(PreCallEvent.getCalleeIdentifier()))
    return;
  const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
  if (!MR)
    return;
  const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);

  // The region must be typed, in order to reason about it.
  if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
    return;

  llvm::SmallVector<const MemRegion *, 2> ReqRegions;
  allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
  if (ReqRegions.empty())
    return;

  ProgramStateRef State = Ctx.getState();
  static CheckerProgramPointTag Tag("MPI-Checker", "UnmatchedWait");
  ExplodedNode *ErrorNode{nullptr};

  // Check all request regions used by the wait function.
  for (const auto &ReqRegion : ReqRegions) {
    const Request *const Req = State->get<RequestMap>(ReqRegion);
    State = State->set<RequestMap>(ReqRegion, Request::State::Wait);
    if (!Req) {
      if (!ErrorNode) {
        ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
        State = ErrorNode->getState();
      }
      // A wait has no matching nonblocking call.
      BReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ErrorNode,
                                    Ctx.getBugReporter());
    }
  }

  if (!ErrorNode) {
    Ctx.addTransition(State);
  } else {
    Ctx.addTransition(State, ErrorNode);
  }
}
Exemplo n.º 10
0
void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const {
  initIdentifierInfo(C.getASTContext());

  if (!Call.isGlobalCFunction())
    return;

  if (Call.getCalleeIdentifier() != IIfopen)
    return;

  // Get the symbolic value corresponding to the file handle.
  SymbolRef FileDesc = Call.getReturnValue().getAsSymbol();
  if (!FileDesc)
    return;

  // Generate the next transition (an edge in the exploded graph).
  ProgramStateRef State = C.getState();
  State = State->set<StreamMap>(FileDesc, StreamState::getOpened());
  C.addTransition(State);
}
void DoubleFetchChecker::checkPreCall(const CallEvent &Call,CheckerContext &Ctx) const {
	const IdentifierInfo *ID = Call.getCalleeIdentifier();
	ProgramStateRef state = Ctx.getState();
	if (ID == NULL) {
		return;
	}
	std::cout<<"[checkPreCall]-----call function:"<<ID->getName().str()<<std::endl;


	if(ID->getName() == "kernel_func") {
		ProgramStateRef state = Ctx.getState();
		SVal arg = Call.getArgSVal(0);
		const MemRegion* mr = arg.getAsRegion();
		/*
		state = state->add<TaintRegionMap>(mr);
		Ctx.addTransition(state);

		SVal val = state->getSVal(mr);
		ProgramStateRef newstate = addTaintToSymExpr(state, val);
		if(newstate){
			Ctx.addTransition(newstate);
			std::cout<<"[checkPreCall] arg add taint finish: "<<toStr(arg)<<std::endl;
		}
		else
			std::cout<<"[checkPreCall] arg add taint failed: "<<toStr(arg)<<std::endl;
*/
	}


	if (ID->getName() == "__builtin___memcpy_chk") {
		SVal Arg0 = Call.getArgSVal(0);
		SVal Arg1 = Call.getArgSVal(1);
		SVal Arg2 = Call.getArgSVal(2);

		const Expr * erg0 = Call.getArgExpr(0);

		const Expr * erg1 = Call.getArgExpr(1);

		const Expr * erg2 = Call.getArgExpr(2);

		if(this->isTaintedByTime(state,Arg0)){
			std::cout<<"[checkPreCall]"<<"\tArg0, tainted, \t "<<std::endl;
			showTaintByTime(state, Arg0);

		}
		else
			std::cout<<"[checkPreCall]"<<"\tArg0, not tainted, \t "<<std::endl;

		if(this->isTaintedByTime(state,Arg1)){
			std::cout<<"[checkPreCall]"<<"\tArg1, tainted, \t "<<std::endl;
			showTaintByTime(state, Arg1);
		}
		else
			std::cout<<"[checkPreCall]"<<"\tArg1, not tainted, \t "<<std::endl;

		if(this->isTaintedByTime(state,Arg2)){
			std::cout<<"[checkPreCall]"<<"\tArg2, tainted, \t "<<std::endl;
			showTaintByTime(state, Arg2);
		}
		else
			std::cout<<"[checkPreCall]"<<"\tArg2, not tainted, \t "<<std::endl;

		if(diffTaintInBranch(state,Arg0,erg0,Ctx.getSourceManager())){
			llvm::errs() << "### Found DF1!!#####\n";
			this->reportDoubleFetch(Ctx, Call);
		}
		if(diffTaintInBranch(state,Arg1,erg1,Ctx.getSourceManager())){
			llvm::errs() << "### Found DF2!!#####\n";
			this->reportDoubleFetch(Ctx, Call);
		}
		if(diffTaintInBranch(state,Arg2,erg2, Ctx.getSourceManager())){
			llvm::errs() << "### Found DF3!!#####\n";
			this->reportDoubleFetch(Ctx, Call);

		}
	}

}
Exemplo n.º 12
0
void DoubleFetchChecker::checkPostCall(const CallEvent &Call,CheckerContext &Ctx) const {
	const IdentifierInfo *ID = Call.getCalleeIdentifier();
	std::cout<<"\n";
	std::cout<<"[checkPostCall]------call function:"<<ID->getName().str()<<std::endl;

	ProgramStateRef state = Ctx.getState();


	if(ID == NULL) {
		return;
	}
	unsigned int curTime = this->getCurTime(state);
	/*everytime copy_from_user is invoked,
	 *a new tainted is added to the taintList of the first Arg,
	 *which is the fetched value in kernel
	 */

	if (ID->getName() == "copy_from_user"){

		SVal Val0 = state->getSVal(Call.getArgExpr(0), Ctx.getLocationContext());
		SVal origin = state->getSVal(Call.getArgExpr(1), Ctx.getLocationContext());
		SVal len = state->getSVal(Call.getArgExpr(2), Ctx.getLocationContext());
		std::cout<<"[checkPostCall]---> Val0: "<<toStr(Val0)<<std::endl;
		std::cout<<"[checkPostCall]---> origin: "<<toStr(origin)<<std::endl;
		std::cout<<"[checkPostCall]---> len: "<<toStr(len)<<std::endl;
		/* here has to use val1 as the origin,
		 * since it is conveted from the actuall Expr
		 */
		state = this->addNewTaint(state, Val0, origin);

		/*after making change to time line, we need to increase the time */
		state = this->increTime(state);
		std::cout<<"[checkPostCall] timer++"<<std::endl;
		if(state != NULL)
			Ctx.addTransition(state);

	}



	if (ID->getName() == "get_user" || ID->getName() =="__get_user"){

			SVal arg0 = Call.getArgSVal(0);
			SVal arg1 = Call.getArgSVal(1);
			std::cout<<"--->arg0: "<<toStr(arg0)<<std::endl;
			std::cout<<"--->arg1: "<<toStr(arg1)<<std::endl;

			//const Expr* e0 = Call.getArgExpr(0);
			//const Expr* e1 =Call.getArgExpr(1);

			/* here has to use val1 as the origin,
			 * since it is conveted from the actuall Expr
			 */
			state = this->addNewTaint(state, arg0, arg1);

			/*after making change to time line, we need to increase the time */
			state = this->increTime(state);
			std::cout<<"[checkPostCall] timer++"<<std::endl;
			if(state != NULL)
				Ctx.addTransition(state);

	}
	if (ID->getName() == "malloc" || ID->getName() == "UserAllocPoolWithQuota") {
		int num = Call.getNumArgs();
		SVal arg = Call.getArgSVal(0);
		SVal ret = Call.getReturnValue();
		/*no need to check by time*/
		if (this->isValTainted(state, arg)){
			std::cout<<"[checkPostCall] arg of malloc is tainted."<<"\targ is:"<<toStr(arg)<<std::endl;
			//pass current taint taint to return value
			ProgramStateRef newstate = passTaints(state, arg, ret);
			if (newstate!=state && newstate != NULL){
				Ctx.addTransition(newstate);
				std::cout<<"[checkPostCall]add ret Taint finish, ret is: "<<toStr(ret)<<std::endl;
				showValTaints(newstate, ret, "--->ret: ");
			}
			else
				std::cout<<"[checkPostCall] add ret Taint failed,  ret is "<<toStr(ret)<<std::endl;
		}

		else{
			std::cout<<"[checkPostCall] arg of malloc not tainted."<<"\targ is:"<<toStr(arg)<<std::endl;
		}
	}
	//int num = Call.getNumArgs();
	//for(int i =0; i< num; i++){
	if (ID->getName() == "CMSG_COMPAT_ALIGN") {
			SVal arg = Call.getArgSVal(0);
			SVal ret = Call.getReturnValue();
			/*no need to check by time*/
			if (this->isValTainted(state, arg)){
				std::cout<<"[checkPostCall] arg of anyfunc is tainted."<<"\targ is:"<<toStr(arg)<<std::endl;
				//pass current taint taint to return value
				ProgramStateRef newstate = passTaints(state, arg, ret);
				if (newstate!=state && newstate != NULL){
					Ctx.addTransition(newstate);
					std::cout<<"[checkPostCall]add ret Taint finish, ret is: "<<toStr(ret)<<std::endl;
					showValTaints(newstate, ret, "--->ret: ");
					return;
				}
				else
					std::cout<<"[checkPostCall] add ret Taint failed,  ret is "<<toStr(ret)<<std::endl;
			}

			else{
				std::cout<<"[checkPostCall] arg of anyfunc not tainted."<<"\targ is:"<<toStr(arg)<<std::endl;
			}
	}

}
Exemplo n.º 13
0
void PHPZPPCheckerImpl::checkPreCall(const CallEvent &Call,
                                     CheckerContext &C) const {
  initIdentifierInfo(C.getASTContext());

  unsigned offset;

  if (!Call.isGlobalCFunction())
    return;

  if (Call.getCalleeIdentifier() == IIzpp) {
    offset = 1;
  } else if (Call.getCalleeIdentifier() == IIzpp_ex) {
    offset = 2;
  } else if (Call.getCalleeIdentifier() == IIzpmp) {
    offset = 2;
  } else if (Call.getCalleeIdentifier() == IIzpmp_ex) {
    offset = 3;
  } else {
    return;
  }

  if (TSRMBuild) {
    ++offset;
  }

  if (Call.getNumArgs() <= offset)
    // Something is really weird - this should be caught by the compiler
    return;

  const StringLiteral *format_spec_sl =
      getCStringLiteral(Call.getArgSVal(offset));
  if (!format_spec_sl) {
    // TODO need a good way to report this, even though this is no error
    std::cout << "Couldn't get format string looked at offset " << offset << std::endl;
    Call.dump();
    return;
  }
  const StringRef format_spec = format_spec_sl->getBytes();

  // Call.dump();
  for (StringRef::const_iterator modifier = format_spec.begin(),
                                 last_mod = format_spec.end();
       modifier != last_mod; ++modifier) {
//std::cout << "  I am checking for " << *modifier << std::endl;
    const PHPTypeRange range = map.equal_range(*modifier);

    if (range.first == range.second) {
      BugReport *R = new BugReport(
          *InvalidModifierBugType,
          std::string("Unknown modifier '") + *modifier + "'", C.addTransition());
      C.emitReport(R);
      return;
    }

    for (PHPTypeMap::const_iterator type = range.first; type != range.second;
         ++type) {
      if (!type->second) {
        // Current modifier doesn't need an argument, these are special things
        // like |, ! or /
        continue;
      }
      ++offset;
//std::cout << "    I need a " << *type->second << " (" << offset << ")" << std::endl;
      if (Call.getNumArgs() <= offset) {
        BugReport *R = new BugReport(*WrongArgumentNumberBugType,
                                     "Too few arguments for format specified",
                                     C.addTransition());
        C.emitReport(R);
//std::cout << "!!!!I am missing args! " << Call.getNumArgs() << "<=" << offset << std::endl;
        return;
      }

      SVal val = Call.getArgSVal(offset);
      if (!compareTypeWithSVal(val, *type->second, C)) {
        // TODO: Move error reporting here?

        // Even if there is a type mismatch we can continue, most of the time
        // this should be a simple mistake by the user, in rare cases the user
        // missed an argument and will get many subsequent errors
      }
    }
  }

  if (Call.getNumArgs() > 1 + offset) {
    BugReport *R = new BugReport(*WrongArgumentNumberBugType,
                                 "Too many arguments for format specified",
                                 C.addTransition());
    R->markInteresting(Call.getArgSVal(offset));
    C.emitReport(R);
  }
}
// Checking for SecItemAdd and SecItemUpdate, no particular reason for assigning it to PostCall
void iOSAppSecInsecureKeyChainStorageChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const 
{
  do
  {
    initIdentifierInfo( C.getASTContext() ) ;

    //redwud: Obviously it is what it is
    if ( !Call.isGlobalCFunction() )
    {
      break ;
    }

    const IdentifierInfo *pCalleeIdent = Call.getCalleeIdentifier() ; 

    // for SecITemAdd() by default
    unsigned int uiParam = 0 ; 
    
    //We do away with array because it's only two of them and it
    //will break the while..passing pattern  
    if ( pCalleeIdent != m_piiSecItemAdd )
    {  
      if ( (pCalleeIdent != m_piiSecItemUpdate) )
      {
        break ;
      }
      else
      {
        uiParam = 1 ;
      }
    }
    
    //Get the query parameter
    //Check if it was recorded as not secure
    //Then create a report
    //Else do nothing

    // Use new method to reuse for checking each parameters, 
    // 1st param for SecItemAdd(), 2nd param for SecItemUpdate() 

    // Get the symbolic value corresponding to the "attributes" parameter.
    SymbolRef pSymToCheck = Call.getArgSVal( uiParam ).getAsSymbol() ;

    //rewud: Not sure how to interpret this, it seems there are no
    //       no symbol for the first parameter 
    if ( !pSymToCheck )
    {
      break ;
    }

    ProgramStateRef pProgState = C.getState() ; 
    
    if ( !isInsecureSymbol( pSymToCheck, pProgState ) ) 
    {
      break ;
    }

    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG( "redwud: ", "!m_pInsecureInstBugType" ) ;
      break ;
    }
 
    //Report this instance
    CMSecCommon::reportInsecureInstance( pSymToCheck, C, C.addTransition( pProgState )
      , *m_pInsecureInstBugType, m_szReportDesc ) ;
  
  } while ( _PASSING_ ) ;

}
Exemplo n.º 15
0
// Checking for SecItemAdd and SecItemUpdate, no particular reason for assigning it to PostCall
void iOSAppSecLeakingLogsChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const 
{
  do
  {
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG( "redwud: ", "!m_pInsecureInstBugType" ) ;
      break ;
    }

    initIdentifierInfo( C.getASTContext() ) ;

    //redwud: Obviously it is what it is
    if ( !Call.isGlobalCFunction() )
    {
      MSEC_DEBUG( "redwud: ", "!Call.isGlobalCFunction" ) ;
      break ;
    }

    const IdentifierInfo *pCalleeIdent = Call.getCalleeIdentifier() ; 

    unsigned iNumArgs = Call.getNumArgs() ; 

    //We do away with array because it's only two of them and it
    //will break the while..passing pattern  
    if ( pCalleeIdent != m_piiNSLog )
    {  
      if ( (pCalleeIdent != m_piiNSLogv) )
      {
        break ;
      }
      //FIXME: Workaround to evade 2nd and onward parameters of NSLogv
      //  Idea: Use identifier for slot from s
      iNumArgs = 1 ;
    }

    CSensitiveInfo &rSenInfo = CSensitiveInfo::create() ;
    SymbolRef pSymToCheck = NULL ; 
   
    // Go through each parameter unless find some sensitive info in one of them
    for ( unsigned iCtr = 0; (iCtr < iNumArgs) && (!pSymToCheck); iCtr++ )
    {
      const Expr *pExpr = Call.getArgExpr( iCtr ) ;
      StringRef szString ;
      StringRef szVarName ;

      CMSecCommon::getStrFromExpr( szString, pExpr, &szVarName ) ; 

      if ( szString.empty() ) // Nil is supported here, so no need to check
      {
//        MSEC_DEBUG( "redwud: ", "Empty string" ) ;
        continue ;
      }

      if ( !rSenInfo.isSensitive( szString.str() ) && !rSenInfo.isSensitive( szVarName.str() ) )
      {
//        MSEC_DEBUG( "redwud: ", "!Sensitive :" << szString << "Var name: " << szVarName ) ;
        continue ; 
      }

      // Get the symbolic value corresponding to the target parameter.
      pSymToCheck = Call.getArgSVal( iCtr ).getAsSymbol() ;
     
      //Force the issue
      if ( !pSymToCheck )
      {
        pSymToCheck = CMSecCommon::conjureSymbolRef() ;
      }
    }

    if ( !pSymToCheck )
    {
      break ;
    }

    ProgramStateRef pProgState = C.getState() ; 

    //Report this instance
    CMSecCommon::reportInsecureInstance( pSymToCheck, C, C.addTransition( pProgState )
      , *m_pInsecureInstBugType, m_szReportDesc ) ;
  
  } while ( _PASSING_ ) ;

}