/** * Select apprioriate function to match the buffer type against * the specified mpi datatype. * * @param typeVisitor contains information about the buffer * @param mpiCall call whose arguments are observed * @param mpiDatatypeString * @param idxPair bufferIdx, mpiDatatypeIdx */ void MPICheckerAST::selectTypeMatcher( const mpi::TypeVisitor &typeVisitor, const MPICall &mpiCall, const StringRef mpiDatatypeString, const std::pair<size_t, size_t> &idxPair) const { const clang::BuiltinType *builtinType = typeVisitor.builtinType(); bool isTypeMatching{true}; // check for exact width types (e.g. int16_t, uint32_t) if (typeVisitor.isTypedefType()) { isTypeMatching = matchExactWidthType(typeVisitor, mpiDatatypeString); } // check for complex-floating types (e.g. float _Complex) else if (typeVisitor.isComplexType()) { isTypeMatching = matchComplexType(typeVisitor, mpiDatatypeString); } // check for basic builtin types (e.g. int, char) else if (!builtinType) { return; // if no builtin type cancel checking } else if (builtinType->isBooleanType()) { isTypeMatching = matchBoolType(typeVisitor, mpiDatatypeString); } else if (builtinType->isAnyCharacterType()) { isTypeMatching = matchCharType(typeVisitor, mpiDatatypeString); } else if (builtinType->isSignedInteger()) { isTypeMatching = matchSignedType(typeVisitor, mpiDatatypeString); } else if (builtinType->isUnsignedIntegerType()) { isTypeMatching = matchUnsignedType(typeVisitor, mpiDatatypeString); } else if (builtinType->isFloatingType()) { isTypeMatching = matchFloatType(typeVisitor, mpiDatatypeString); } if (!isTypeMatching) bugReporter_.reportTypeMismatch(mpiCall.callExpr(), idxPair, typeVisitor.qualType_, mpiDatatypeString); }
bool MPICheckerAST::matchCharType(const mpi::TypeVisitor &visitor, const llvm::StringRef mpiDatatype) const { bool isTypeMatching; switch (visitor.builtinType()->getKind()) { case BuiltinType::SChar: isTypeMatching = (mpiDatatype == "MPI_CHAR" || mpiDatatype == "MPI_SIGNED_CHAR"); break; case BuiltinType::Char_S: isTypeMatching = (mpiDatatype == "MPI_CHAR" || mpiDatatype == "MPI_SIGNED_CHAR"); break; case BuiltinType::UChar: isTypeMatching = (mpiDatatype == "MPI_UNSIGNED_CHAR"); break; case BuiltinType::Char_U: isTypeMatching = (mpiDatatype == "MPI_UNSIGNED_CHAR"); break; case BuiltinType::WChar_S: isTypeMatching = (mpiDatatype == "MPI_WCHAR"); break; case BuiltinType::WChar_U: isTypeMatching = (mpiDatatype == "MPI_WCHAR"); break; default: isTypeMatching = true; } return isTypeMatching; }
/** * Checks if buffer type and specified mpi datatype matches. * * @param mpiCall call to check type correspondence for */ void MPICheckerAST::checkBufferTypeMatch( const clang::CallExpr *const mpiCall) const { // one pair consists of {bufferIdx, mpiDatatypeIdx} IndexPairs indexPairs = bufferDataTypeIndices(mpiCall); // for every buffer mpi-data pair in function // check if their types match for (const auto &idxPair : indexPairs) { auto bufferType = mpiCall->getArg(idxPair.first)->IgnoreImpCasts()->getType(); // collect buffer type information const mpi::TypeVisitor typeVisitor { bufferType }; // get mpi datatype as string StringRef mpiDatatypeString{util::sourceRangeAsStringRef( mpiCall->getArg(idxPair.second)->getSourceRange(), analysisManager_)}; // check if buffer is correctly referenced if (typeVisitor.pointerCount() != 1) { bugReporter_.reportIncorrectBufferReferencing( mpiCall, idxPair, bufferType, typeVisitor.pointerCount()); } // MPI_BYTE needs no matching if (mpiDatatypeString == "MPI_BYTE") return; // if MPI type not known if (!cont::isContained(mpiTypes_, mpiDatatypeString)) return; selectTypeMatcher(typeVisitor, mpiCall, mpiDatatypeString, idxPair); } }
bool MPICheckerAST::matchExactWidthType( const mpi::TypeVisitor &visitor, const llvm::StringRef mpiDatatype) const { // check typedef type match // no break needs to be specified for string switch bool isTypeMatching = llvm::StringSwitch<bool>(visitor.typedefTypeName()) .Case("int8_t", (mpiDatatype == "MPI_INT8_T")) .Case("int16_t", (mpiDatatype == "MPI_INT16_T")) .Case("int32_t", (mpiDatatype == "MPI_INT32_T")) .Case("int64_t", (mpiDatatype == "MPI_INT64_T")) .Case("uint8_t", (mpiDatatype == "MPI_UINT8_T")) .Case("uint16_t", (mpiDatatype == "MPI_UINT16_T")) .Case("uint32_t", (mpiDatatype == "MPI_UINT32_T")) .Case("uint64_t", (mpiDatatype == "MPI_UINT64_T")) // unknown typedefs are rated as correct .Default(true); return isTypeMatching; }
bool MPICheckerAST::matchFloatType(const mpi::TypeVisitor &visitor, const llvm::StringRef mpiDatatype) const { bool isTypeMatching; switch (visitor.builtinType()->getKind()) { case BuiltinType::Float: isTypeMatching = (mpiDatatype == "MPI_FLOAT"); break; case BuiltinType::Double: isTypeMatching = (mpiDatatype == "MPI_DOUBLE"); break; case BuiltinType::LongDouble: isTypeMatching = (mpiDatatype == "MPI_LONG_DOUBLE"); break; default: isTypeMatching = true; } return isTypeMatching; }
bool MPICheckerAST::matchUnsignedType(const mpi::TypeVisitor &visitor, const llvm::StringRef mpiDatatype) const { bool isTypeMatching; switch (visitor.builtinType()->getKind()) { case BuiltinType::UInt: isTypeMatching = (mpiDatatype == "MPI_UNSIGNED"); break; case BuiltinType::UShort: isTypeMatching = (mpiDatatype == "MPI_UNSIGNED_SHORT"); break; case BuiltinType::ULong: isTypeMatching = (mpiDatatype == "MPI_UNSIGNED_LONG"); break; case BuiltinType::ULongLong: isTypeMatching = (mpiDatatype == "MPI_UNSIGNED_LONG_LONG"); break; default: isTypeMatching = true; } return isTypeMatching; }
/** * Check if invalid argument types are used in a mpi call. * This check looks at indices where only integer values are valid. * (count, rank, tag) Any non integer type usage is reported. * * @param mpiCall to check the arguments for */ void MPICheckerAST::checkForInvalidArgs(const MPICall &mpiCall) const { std::vector<size_t> indicesToCheck = integerIndices(mpiCall); if (!indicesToCheck.size()) return; // iterate indices which should not have integer arguments for (const size_t idx : indicesToCheck) { // check for invalid variable types const auto &arg = mpiCall.arguments()[idx]; const auto &vars = arg.vars(); for (const auto &var : vars) { const mpi::TypeVisitor typeVisitor{var->getType()}; if (!typeVisitor.builtinType() || !typeVisitor.builtinType()->isIntegerType()) { bugReporter_.reportInvalidArgumentType( mpiCall.callExpr(), idx, var->getSourceRange(), "Variable"); } } // check for float literals if (arg.floatingLiterals().size()) { bugReporter_.reportInvalidArgumentType( mpiCall.callExpr(), idx, arg.floatingLiterals().front()->getSourceRange(), "Literal"); } // check for invalid return types from functions const auto &functions = arg.functions(); for (const auto &function : functions) { const mpi::TypeVisitor typeVisitor{function->getReturnType()}; if (!typeVisitor.builtinType() || !typeVisitor.builtinType()->isIntegerType()) { bugReporter_.reportInvalidArgumentType( mpiCall.callExpr(), idx, function->getSourceRange(), "Return value"); } } } }