[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