[clang] [Clang][Sema] Add fortify warnings for recv and recvfrom (PR #223520)
Venkatesh Srinivasan via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 14 13:57:00 PDT 2026
https://github.com/venk-ks updated https://github.com/llvm/llvm-project/pull/223520
>From 43299adfad1867521559523e214701cc139d0c78 Mon Sep 17 00:00:00 2001
From: Venkatesh Srinivasan <venk at google.com>
Date: Mon, 14 Sep 2026 20:41:13 +0000
Subject: [PATCH] [Clang][Sema] Add fortify warnings for recv and recvfrom
Add -Wfortify-source diagnostics for recv, recvfrom, and their
__builtin_ prefixed aliases when the size argument exceeds the
destination buffer size.
Part of #142230
Assisted-by: Gemini
---
clang/docs/ReleaseNotes.md | 5 +++
clang/include/clang/Basic/BuiltinHeaders.def | 1 +
clang/include/clang/Basic/Builtins.td | 16 ++++++++
clang/lib/Sema/SemaChecking.cpp | 12 ++++++
clang/test/Sema/warn-fortify-source.c | 40 ++++++++++++++++++++
5 files changed, 74 insertions(+)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 043a0ddae2a6c..ad6c20f8322c5 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -236,6 +236,8 @@ features cannot lower the translation-unit ABI level;
- Added support for the `__builtin_strlcat` and `__builtin_strlcpy` builtins.
+- Added support for the `__builtin_recv` and `__builtin_recvfrom` builtins.
+
### New Compiler Flags
- New option `-fdefined-pointer-subtraction` added to preserve stable semantics
@@ -276,6 +278,9 @@ features cannot lower the translation-unit ABI level;
- `-Wfortify-source` now diagnoses when `strlcat`, `__builtin_strlcat`, `strlcpy`, or
`__builtin_strlcpy` is called with a size argument larger than the destination buffer.
+- `-Wfortify-source` now diagnoses when `recv`, `__builtin_recv`, `recvfrom`, or
+ `__builtin_recvfrom` is called with a size argument larger than the destination buffer.
+
- The `cannot overload a member function` diagnostic now describes the previous
declaration first, matching the order in which the declarations appear in the
source. (#GH219803)
diff --git a/clang/include/clang/Basic/BuiltinHeaders.def b/clang/include/clang/Basic/BuiltinHeaders.def
index b18e470a8bd25..73a8e387cc4cb 100644
--- a/clang/include/clang/Basic/BuiltinHeaders.def
+++ b/clang/include/clang/Basic/BuiltinHeaders.def
@@ -38,6 +38,7 @@ HEADER(STDIO_H, "stdio.h")
HEADER(STDLIB_H, "stdlib.h")
HEADER(STRINGS_H, "strings.h")
HEADER(STRING_H, "string.h")
+HEADER(SYS_SOCKET_H, "sys/socket.h")
HEADER(SYS_STAT_H, "sys/stat.h")
HEADER(UNISTD_H, "unistd.h")
HEADER(UTILITY, "utility")
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index d148cb4b9101e..7822144cfb988 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3868,6 +3868,22 @@ def Umask : LibBuiltin<"sys/stat.h"> {
let Prototype = ""; // mode_t(mode_t); mode_t is target-specific
}
+// POSIX sys/socket.h
+
+def Recv : LibBuiltin<"sys/socket.h"> {
+ let Spellings = ["recv"];
+ let Attributes = [IgnoreSignature, NoThrow];
+ let Prototype = "";
+ let AddBuiltinPrefixedAlias = 1;
+}
+
+def RecvFrom : LibBuiltin<"sys/socket.h"> {
+ let Spellings = ["recvfrom"];
+ let Attributes = [IgnoreSignature, NoThrow];
+ let Prototype = "";
+ let AddBuiltinPrefixedAlias = 1;
+}
+
// POSIX pthread.h
def PthreadCreate : GNULibBuiltin<"pthread.h"> {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ac333d5b66662..f39abc18c6cab 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1467,6 +1467,18 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
break;
}
+ case Builtin::BIrecv:
+ case Builtin::BI__builtin_recv:
+ case Builtin::BIrecvfrom:
+ case Builtin::BI__builtin_recvfrom: {
+ if (TheCall->getNumArgs() < 3)
+ return;
+ DiagID = diag::warn_fortify_source_size_mismatch;
+ SourceSize = Checker.ComputeExplicitObjectSizeArgument(2);
+ DestinationSize = Checker.ComputeSizeArgument(1);
+ break;
+ }
+
case Builtin::BIbzero:
case Builtin::BI__builtin_bzero:
case Builtin::BImemcpy:
diff --git a/clang/test/Sema/warn-fortify-source.c b/clang/test/Sema/warn-fortify-source.c
index 8339efddc5b3e..3e07221e4cafd 100644
--- a/clang/test/Sema/warn-fortify-source.c
+++ b/clang/test/Sema/warn-fortify-source.c
@@ -9,6 +9,9 @@
// RUN: %clang_cc1 -xc++ -triple x86_64-apple-macosx10.14.0 %s -verify -DUSE_BUILTINS -fexperimental-new-constant-interpreter
typedef unsigned long size_t;
+typedef long ssize_t;
+typedef unsigned int socklen_t;
+struct sockaddr;
#ifdef __cplusplus
extern "C" {
@@ -23,6 +26,10 @@ void *memcpy(void *dst, const void *src, size_t c);
#endif
void bcopy(const void *src, void *dst, size_t n);
void bzero(void *dst, size_t n);
+ssize_t recv(int, void *, size_t, int);
+ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
+ssize_t __builtin_recv(int, void *, size_t, int);
+ssize_t __builtin_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
#ifdef __cplusplus
}
@@ -270,6 +277,39 @@ void call_umask(mode_t runtime_mode) {
umask(runtime_mode); // no warning, not a constant
}
+void call_recv(int fd) {
+ char buf[10];
+ recv(fd, buf, 10, 0);
+ recv(fd, buf, 11, 0); // expected-warning {{'recv' size argument is too large; destination buffer has size 10, but size argument is 11}}
+ __builtin_recv(fd, buf, 10, 0);
+ __builtin_recv(fd, buf, 11, 0); // expected-warning {{'recv' size argument is too large; destination buffer has size 10, but size argument is 11}}
+}
+
+void call_recvfrom(int fd) {
+ char buf[10];
+ recvfrom(fd, buf, 10, 0, (struct sockaddr *)0, (socklen_t *)0);
+ recvfrom(fd, buf, 11, 0, (struct sockaddr *)0, (socklen_t *)0); // expected-warning {{'recvfrom' size argument is too large; destination buffer has size 10, but size argument is 11}}
+ __builtin_recvfrom(fd, buf, 10, 0, (struct sockaddr *)0, (socklen_t *)0);
+ __builtin_recvfrom(fd, buf, 11, 0, (struct sockaddr *)0, (socklen_t *)0); // expected-warning {{'recvfrom' size argument is too large; destination buffer has size 10, but size argument is 11}}
+}
+
+void call_recv_subobject(int fd) {
+ struct {
+ char first[10];
+ char second[20];
+ } s;
+ recv(fd, s.first, 35, 0); // expected-warning {{'recv' size argument is too large; destination buffer has size 30, but size argument is 35}}
+ __builtin_recv(fd, s.first, 35, 0); // expected-warning {{'recv' size argument is too large; destination buffer has size 30, but size argument is 35}}
+}
+
+void call_recv_runtime(int fd, size_t n) {
+ char buf[10];
+ recv(fd, buf, n, 0);
+ recvfrom(fd, buf, n, 0, (struct sockaddr *)0, (socklen_t *)0);
+ __builtin_recv(fd, buf, n, 0);
+ __builtin_recvfrom(fd, buf, n, 0, (struct sockaddr *)0, (socklen_t *)0);
+}
+
#ifdef __cplusplus
template <class> struct S {
void mf() const {
More information about the cfe-commits
mailing list