================
@@ -1165,7 +1165,103 @@ void 
Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
 
   unsigned BuiltinID = UseDecl->getBuiltinID(/*ConsiderWrappers=*/true);
 
-  if (!BuiltinID)
+  // Some libc I/O functions are intentionally not Clang builtins:
+  //   * "read", "write", "readlink", "readlinkat", and "getcwd" are common
+  //     identifiers (or names that appear in asm-label wrappers); declaring
+  //     them as builtins triggers -Wincompatible-library-redeclaration on
+  //     harmless local declarations (an error under -Werror).
+  //   * pread/pwrite prototypes use off_t, whose width is platform- and
+  //     macro-dependent (notably _FILE_OFFSET_BITS); a fixed builtin signature
+  //     would clash with the system header on some targets.
+  // Recognize them by name, but only after checking the full POSIX prototype
+  // so that an unrelated function happening to share the name is not
+  // diagnosed as if it were the libc function.
+  struct LibcFuncDesc {
+    StringRef Name;
+    QualType Return;
+    SmallVector<QualType, 4> Params;
+    std::optional<unsigned> SourceSizeIdx; // __bos buffer; reads from
+    std::optional<unsigned> MaxOpSizeIdx;  // count arg (constant-evaluated)
+    std::optional<unsigned> DestSizeIdx;   // __bos buffer; writes to
+  };
+
+  std::optional<LibcFuncDesc> LibCMatch;
+  if (!BuiltinID && FD->isExternC() && FD->getIdentifier() &&
+      !FD->isVariadic()) {
+    ASTContext &Ctx = getASTContext();
+    QualType IntTy = Ctx.IntTy;
+    QualType SizeTy = Ctx.getSizeType();
+    QualType VoidPtrTy = Ctx.VoidPtrTy;
+    QualType ConstVoidPtrTy = Ctx.getPointerType(Ctx.VoidTy.withConst());
+    QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+    QualType ConstCharPtrTy = Ctx.getPointerType(Ctx.CharTy.withConst());
+    // ssize_t / off_t / off64_t aren't single Clang types (ssize_t differs
+    // across libcs, off_t depends on _FILE_OFFSET_BITS, off64_t is always
+    // 64-bit). The name match has already pinned us to POSIX intent, so
+    // MatchSlot below treats any integer-typed slot as compatible with any
+    // integer-typed argument; these aliases just keep the table readable.
+    QualType SSizeTy = IntTy;
+    QualType OffTy = IntTy;
+    QualType Off64Ty = IntTy;
+
+    // Same unqualified type, or both integer types: accepts libc typedef
+    // divergence (ssize_t/off_t/off64_t) while still rejecting pointer or
+    // aggregate mismatches.
+    auto MatchSlot = [&](QualType Expected, QualType Actual) {
+      if (Ctx.hasSameUnqualifiedType(Expected, Actual))
+        return true;
+      return Expected->isIntegerType() && Actual->isIntegerType();
+    };
+
+    auto Make = [](StringRef Name, QualType Ret,
+                   std::initializer_list<QualType> Params,
+                   std::optional<unsigned> Src, std::optional<unsigned> MaxOp,
+                   std::optional<unsigned> Dest) {
+      return LibcFuncDesc{Name, Ret, Params, Src, MaxOp, Dest};
+    };
+
+    auto LookupLibc = [&](StringRef Name) -> std::optional<LibcFuncDesc> {
+      if (Name == "getcwd")
+        return Make(Name, CharPtrTy, {CharPtrTy, SizeTy}, std::nullopt, 1, 0);
+      if (Name == "read")
+        return Make(Name, SSizeTy, {IntTy, VoidPtrTy, SizeTy}, std::nullopt, 2,
+                    1);
----------------
ojhunt wrote:

I'd put all these in a lazily constructed unique_ptr<densemap<StringRef, 
LibcFuncDesc>>, and the you can have a fairly clear

DenseMap init with {{"write", {SSizeTy, {IntTy, ConstVoidPtrTy, SizeTy}, ...}, 
{"readlink",...

and a std::optional<LibcFuncDesc> lookupLibCFunctionDesc(StringRef);



https://github.com/llvm/llvm-project/pull/196499
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to