Exemple #1
0
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                              ProgramStateRef state,
                                              ObjCMessage msg) const {
  ASTContext &Ctx = C.getASTContext();

  // Check the return type of the message expression.  A message to nil will
  // return different values depending on the return type and the architecture.
  QualType RetTy = msg.getType(Ctx);
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
  const LocationContext *LCtx = C.getLocationContext();

  if (CanRetTy->isStructureOrClassType()) {
    // Structure returns are safe since the compiler zeroes them out.
    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
    C.addTransition(state->BindExpr(msg.getOriginExpr(), LCtx, V));
    return;
  }

  // Other cases: check if sizeof(return type) > sizeof(void*)
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
                                  .isConsumedExpr(msg.getOriginExpr())) {
    // Compute: sizeof(void *) and sizeof(return type)
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);

    if (voidPtrSize < returnTypeSize &&
        !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
          (Ctx.FloatTy == CanRetTy ||
           Ctx.DoubleTy == CanRetTy ||
           Ctx.LongDoubleTy == CanRetTy ||
           Ctx.LongLongTy == CanRetTy ||
           Ctx.UnsignedLongLongTy == CanRetTy))) {
      if (ExplodedNode *N = C.generateSink(state))
        emitNilReceiverBug(C, msg, N);
      return;
    }

    // Handle the safe cases where the return value is 0 if the
    // receiver is nil.
    //
    // FIXME: For now take the conservative approach that we only
    // return null values if we *know* that the receiver is nil.
    // This is because we can have surprises like:
    //
    //   ... = [[NSScreens screens] objectAtIndex:0];
    //
    // What can happen is that [... screens] could return nil, but
    // it most likely isn't nil.  We should assume the semantics
    // of this case unless we have *a lot* more knowledge.
    //
    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
    C.addTransition(state->BindExpr(msg.getOriginExpr(), LCtx, V));
    return;
  }

  C.addTransition(state);
}
void ObjCSelfInitChecker::checkPostObjCMessage(ObjCMessage msg,
                                               CheckerContext &C) const {
  // When encountering a message that does initialization (init rule),
  // tag the return value so that we know later on that if self has this value
  // then it is properly initialized.

  // FIXME: A callback should disable checkers at the start of functions.
  if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
                                     C.getCurrentAnalysisDeclContext()->getDecl())))
    return;

  if (isInitMessage(msg)) {
    // Tag the return value as the result of an initializer.
    const ProgramState *state = C.getState();
    
    // FIXME this really should be context sensitive, where we record
    // the current stack frame (for IPA).  Also, we need to clean this
    // value out when we return from this method.
    state = state->set<CalledInit>(true);
    
    SVal V = state->getSVal(msg.getOriginExpr(), C.getLocationContext());
    addSelfFlag(state, V, SelfFlag_InitRes, C);
    return;
  }

  // We don't check for an invalid 'self' in an obj-c message expression to cut
  // down false positives where logging functions get information from self
  // (like its class) or doing "invalidation" on self when the initialization
  // fails.
}