SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite CS) { Optional<AllocFnsTy> FnData = getAllocationSize(CS.getInstruction(), TLI); if (!FnData) return unknown(); // Handle strdup-like functions separately. if (FnData->AllocTy == StrDupLike) { APInt Size(IntTyBits, GetStringLength(CS.getArgument(0))); if (!Size) return unknown(); // Strndup limits strlen. if (FnData->FstParam > 0) { ConstantInt *Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->FstParam)); if (!Arg) return unknown(); APInt MaxSize = Arg->getValue().zextOrSelf(IntTyBits); if (Size.ugt(MaxSize)) Size = MaxSize + 1; } return std::make_pair(Size, Zero); } ConstantInt *Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->FstParam)); if (!Arg) return unknown(); APInt Size = Arg->getValue(); if (!CheckedZextOrTrunc(Size)) return unknown(); // Size is determined by just 1 parameter. if (FnData->SndParam < 0) return std::make_pair(Size, Zero); Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->SndParam)); if (!Arg) return unknown(); APInt NumElems = Arg->getValue(); if (!CheckedZextOrTrunc(NumElems)) return unknown(); bool Overflow; Size = Size.umul_ov(NumElems, Overflow); return Overflow ? unknown() : std::make_pair(Size, Zero); // TODO: handle more standard functions (+ wchar cousins): // - strdup / strndup // - strcpy / strncpy // - strcat / strncat // - memcpy / memmove // - strcat / strncat // - memset }
APInt swift::constantFoldBinaryWithOverflow(APInt lhs, APInt rhs, bool &Overflow, llvm::Intrinsic::ID ID) { switch (ID) { default: llvm_unreachable("Invalid case"); case llvm::Intrinsic::sadd_with_overflow: return lhs.sadd_ov(rhs, Overflow); case llvm::Intrinsic::uadd_with_overflow: return lhs.uadd_ov(rhs, Overflow); case llvm::Intrinsic::ssub_with_overflow: return lhs.ssub_ov(rhs, Overflow); case llvm::Intrinsic::usub_with_overflow: return lhs.usub_ov(rhs, Overflow); case llvm::Intrinsic::smul_with_overflow: return lhs.smul_ov(rhs, Overflow); case llvm::Intrinsic::umul_with_overflow: return lhs.umul_ov(rhs, Overflow); } }
SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite CS) { Optional<AllocFnsTy> FnData = getAllocationSize(CS.getInstruction(), TLI); if (!FnData) return unknown(); // Handle strdup-like functions separately. if (FnData->AllocTy == StrDupLike) { APInt Size(IntTyBits, GetStringLength(CS.getArgument(0))); if (!Size) return unknown(); // Strndup limits strlen. if (FnData->FstParam > 0) { ConstantInt *Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->FstParam)); if (!Arg) return unknown(); APInt MaxSize = Arg->getValue().zextOrSelf(IntTyBits); if (Size.ugt(MaxSize)) Size = MaxSize + 1; } return std::make_pair(Size, Zero); } ConstantInt *Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->FstParam)); if (!Arg) return unknown(); // When we're compiling N-bit code, and the user uses parameters that are // greater than N bits (e.g. uint64_t on a 32-bit build), we can run into // trouble with APInt size issues. This function handles resizing + overflow // checks for us. auto CheckedZextOrTrunc = [&](APInt &I) { // More bits than we can handle. Checking the bit width isn't necessary, but // it's faster than checking active bits, and should give `false` in the // vast majority of cases. if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits) return false; if (I.getBitWidth() != IntTyBits) I = I.zextOrTrunc(IntTyBits); return true; }; APInt Size = Arg->getValue(); if (!CheckedZextOrTrunc(Size)) return unknown(); // Size is determined by just 1 parameter. if (FnData->SndParam < 0) return std::make_pair(Size, Zero); Arg = dyn_cast<ConstantInt>(CS.getArgument(FnData->SndParam)); if (!Arg) return unknown(); APInt NumElems = Arg->getValue(); if (!CheckedZextOrTrunc(NumElems)) return unknown(); bool Overflow; Size = Size.umul_ov(NumElems, Overflow); return Overflow ? unknown() : std::make_pair(Size, Zero); // TODO: handle more standard functions (+ wchar cousins): // - strdup / strndup // - strcpy / strncpy // - strcat / strncat // - memcpy / memmove // - strcat / strncat // - memset }