[libc-commits] [libc] [libc] Make struct ifreq compatible with linux/if.h (PR #225793)

via libc-commits libc-commits at lists.llvm.org
Wed Sep 23 07:25:37 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Pavel Labath (labath)

<details>
<summary>Changes</summary>

When <linux/if.h> is included after <net/if.h>, compilation fails for two reasons:
- <linux/libc-compat.h> expects libc to coordinate using the __UAPI_DEF_IF_IFREQ macro. Because we didn't define it, the kernel headers fell back to defining it as 1, which caused <linux/if.h> to redefine struct ifreq.
- <linux/if.h> defines field access macros (ifr_name, ifr_addr, etc.) pointing to members of named ifr_ifrn and ifr_ifru unions. Our struct ifreq used an anonymous union, so those defines broke member access.

To fix this:
- define __UAPI_DEF_IF_IFREQ 0 to prevent the kernel header from defining the struct
- modify `struct ifreq` to use named ifr_ifrn and ifr_ifru unions and defining matching member macros. This is necessary because kernel headers define the member macros even in the __UAPI_DEF_IF_IFREQ==0 case.
- add an include test in test/include/net/linux to verify that including <linux/if.h> after <net/if.h> works as expected

While in there, I also move the struct definition into a linux subfolder, as the type is linux-specific.

It's worth noting that including the headers in the opposite direction is still broken, but that is also true for all other libc implementations.

Assisted-by: Gemini

---
Full diff: https://github.com/llvm/llvm-project/pull/225793.diff


8 Files Affected:

- (modified) libc/include/llvm-libc-types/CMakeLists.txt (+8-3) 
- (modified) libc/include/llvm-libc-types/linux/CMakeLists.txt (+9) 
- (added) libc/include/llvm-libc-types/linux/struct_ifreq.h (+59) 
- (modified) libc/include/llvm-libc-types/struct_ifreq.h (+3-22) 
- (modified) libc/test/include/CMakeLists.txt (+2) 
- (added) libc/test/include/net/CMakeLists.txt (+4) 
- (added) libc/test/include/net/linux/CMakeLists.txt (+10) 
- (added) libc/test/include/net/linux/net_if_and_linux_if_test.cpp (+27) 


``````````diff
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index ea710ef48857cf..c0db5ab81f382f 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -30,6 +30,9 @@ function(add_type_header name)
   )
 endfunction()
 
+add_header(sa_family_t HDR sa_family_t.h)
+add_header(struct_sockaddr HDR struct_sockaddr.h DEPENDS .sa_family_t)
+
 if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
   add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
 endif()
@@ -263,9 +266,7 @@ add_header(
 )
 add_header(wint_t HDR wint_t.h)
 add_header(wctype_t HDR wctype_t.h)
-add_header(sa_family_t HDR sa_family_t.h)
 add_header(socklen_t HDR socklen_t.h)
-add_header(struct_sockaddr HDR struct_sockaddr.h DEPENDS .sa_family_t)
 add_header(struct_addrinfo HDR struct_addrinfo.h DEPENDS .socklen_t .struct_sockaddr)
 add_header(struct_sockaddr_in HDR struct_sockaddr_in.h DEPENDS .in_port_t .sa_family_t .struct_in_addr)
 add_header(
@@ -296,7 +297,11 @@ add_header(
     libc.include.llvm-libc-macros.stdint_macros
 )
 add_header(struct_sockaddr_un HDR struct_sockaddr_un.h DEPENDS .sa_family_t)
-add_header(struct_ifreq HDR struct_ifreq.h DEPENDS libc.include.llvm-libc-macros.net_if_macros .struct_sockaddr)
+add_type_header(
+  struct_ifreq
+  HDR
+    struct_ifreq.h
+)
 add_header(struct_if_nameindex HDR struct_if_nameindex.h)
 add_header(struct_iovec HDR struct_iovec.h DEPENDS .size_t)
 add_header(struct_linger HDR struct_linger.h)
diff --git a/libc/include/llvm-libc-types/linux/CMakeLists.txt b/libc/include/llvm-libc-types/linux/CMakeLists.txt
index d937ffe30e6e82..95a91af15848ff 100644
--- a/libc/include/llvm-libc-types/linux/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/linux/CMakeLists.txt
@@ -9,3 +9,12 @@ add_header(
   HDR
     struct_sysinfo.h
 )
+
+add_header(
+  struct_ifreq
+  HDR
+    struct_ifreq.h
+  DEPENDS
+    libc.include.llvm-libc-macros.net_if_macros
+    libc.include.llvm-libc-types.struct_sockaddr
+)
diff --git a/libc/include/llvm-libc-types/linux/struct_ifreq.h b/libc/include/llvm-libc-types/linux/struct_ifreq.h
new file mode 100644
index 00000000000000..44a7df05034166
--- /dev/null
+++ b/libc/include/llvm-libc-types/linux/struct_ifreq.h
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of struct ifreq for Linux.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_LINUX_STRUCT_IFREQ_H
+#define LLVM_LIBC_TYPES_LINUX_STRUCT_IFREQ_H
+
+#include "../../llvm-libc-macros/net-if-macros.h"
+#include "../struct_sockaddr.h"
+
+// Prevent the linux headers from defining this type.
+#define __UAPI_DEF_IF_IFREQ 0
+
+struct ifreq {
+  union {
+    char ifrn_name[IF_NAMESIZE];
+  } ifr_ifrn;
+
+  union {
+    struct sockaddr ifru_addr;
+    struct sockaddr ifru_dstaddr;
+    struct sockaddr ifru_broadaddr;
+    struct sockaddr ifru_netmask;
+    struct sockaddr ifru_hwaddr;
+    short int ifru_flags;
+    int ifru_ivalue;
+    int ifru_mtu;
+    char ifru_slave[IF_NAMESIZE];
+    char ifru_newname[IF_NAMESIZE];
+    char *ifru_data;
+  } ifr_ifru;
+};
+
+#define ifr_name ifr_ifrn.ifrn_name
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr
+#define ifr_addr ifr_ifru.ifru_addr
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr
+#define ifr_netmask ifr_ifru.ifru_netmask
+#define ifr_flags ifr_ifru.ifru_flags
+#define ifr_metric ifr_ifru.ifru_ivalue
+#define ifr_mtu ifr_ifru.ifru_mtu
+#define ifr_slave ifr_ifru.ifru_slave
+#define ifr_data ifr_ifru.ifru_data
+#define ifr_ifindex ifr_ifru.ifru_ivalue
+#define ifr_bandwidth ifr_ifru.ifru_ivalue
+#define ifr_qlen ifr_ifru.ifru_ivalue
+#define ifr_newname ifr_ifru.ifru_newname
+
+#endif // LLVM_LIBC_TYPES_LINUX_STRUCT_IFREQ_H
diff --git a/libc/include/llvm-libc-types/struct_ifreq.h b/libc/include/llvm-libc-types/struct_ifreq.h
index b9ad182f978020..0a08f94eefb7c7 100644
--- a/libc/include/llvm-libc-types/struct_ifreq.h
+++ b/libc/include/llvm-libc-types/struct_ifreq.h
@@ -14,27 +14,8 @@
 #ifndef LLVM_LIBC_TYPES_STRUCT_IFREQ_H
 #define LLVM_LIBC_TYPES_STRUCT_IFREQ_H
 
-#include "../llvm-libc-macros/net-if-macros.h"
-#include "struct_sockaddr.h"
-
-struct ifreq {
-  char ifr_name[IF_NAMESIZE];
-  __extension__ union {
-    struct sockaddr ifr_hwaddr;
-    struct sockaddr ifr_addr;
-    struct sockaddr ifr_dstaddr;
-    struct sockaddr ifr_broadaddr;
-    struct sockaddr ifr_netmask;
-    short int ifr_flags;
-    int ifr_metric;
-    int ifr_mtu;
-    int ifr_ifindex;
-    int ifr_bandwidth;
-    int ifr_qlen;
-    char ifr_newname[IF_NAMESIZE];
-    char ifr_slave[IF_NAMESIZE];
-    char *ifr_data;
-  };
-};
+#if defined(__linux__)
+#include "linux/struct_ifreq.h"
+#endif
 
 #endif // LLVM_LIBC_TYPES_STRUCT_IFREQ_H
diff --git a/libc/test/include/CMakeLists.txt b/libc/test/include/CMakeLists.txt
index c2cfa416972c32..b2fb07f9c3def0 100644
--- a/libc/test/include/CMakeLists.txt
+++ b/libc/test/include/CMakeLists.txt
@@ -246,6 +246,8 @@ add_libc_test(
     libc.include.llvm-libc-macros.netinet_in_macros
 )
 
+add_subdirectory(net)
+
 add_libc_test(
   signbit_test
   SUITE
diff --git a/libc/test/include/net/CMakeLists.txt b/libc/test/include/net/CMakeLists.txt
new file mode 100644
index 00000000000000..8e285dd5b94c53
--- /dev/null
+++ b/libc/test/include/net/CMakeLists.txt
@@ -0,0 +1,4 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${LIBC_TARGET_OS})
+endif()
+
diff --git a/libc/test/include/net/linux/CMakeLists.txt b/libc/test/include/net/linux/CMakeLists.txt
new file mode 100644
index 00000000000000..b83b00a822989c
--- /dev/null
+++ b/libc/test/include/net/linux/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_libc_test(
+  net_if_and_linux_if_test
+  SUITE
+    libc_include_tests
+  SRCS
+    net_if_and_linux_if_test.cpp
+  DEPENDS
+    libc.include.net_if
+)
+
diff --git a/libc/test/include/net/linux/net_if_and_linux_if_test.cpp b/libc/test/include/net/linux/net_if_and_linux_if_test.cpp
new file mode 100644
index 00000000000000..a1c56bf4e556b0
--- /dev/null
+++ b/libc/test/include/net/linux/net_if_and_linux_if_test.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for net/if.h and linux/if.h compatibility.
+///
+//===----------------------------------------------------------------------===//
+
+// Include our header first.
+#include <net/if.h>
+
+// And Linux header afterwards. The blank line prevents clang-format from
+// reordering these.
+#include <linux/if.h>
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcNetIfAndLinuxIfTest, LinuxIfAfterNetIf) {
+  // Test that <linux/if.h> can be included after <net/if.h>.
+  struct ifreq ifr;
+  (void)ifr;
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/225793


More information about the libc-commits mailing list