Fix ifaddrs error handling.
An NLMSG_ERROR packet includes an errno value that we should use. Also report
failures to create a socket immediately, rather than falling through to the
send and reporting EBADF.
Bug: http://b/32145516
Bug: http://b/31038971
Test: bionic ifaddr tests on ryu (with broken kernel) and flounder
Change-Id: I84c480c5b75077eb90d40426a9d66d7bffbd3d51
diff --git a/tests/ifaddrs_test.cpp b/tests/ifaddrs_test.cpp
index 9f01619..4b9d4d8 100644
--- a/tests/ifaddrs_test.cpp
+++ b/tests/ifaddrs_test.cpp
@@ -19,6 +19,7 @@
#include <ifaddrs.h>
#include <dirent.h>
+#include <fcntl.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
@@ -28,6 +29,7 @@
#include <algorithm>
#include <map>
+#include <thread>
#include <vector>
TEST(ifaddrs, freeifaddrs_null) {
@@ -267,3 +269,40 @@
freeifaddrs(addrs);
}
+
+TEST(ifaddrs, kernel_bug_31038971) {
+ // Some kernels had a bug that would lead to an NLMSG_ERROR response,
+ // but bionic wasn't setting errno based on the value in the message.
+ // This is the test for the kernel bug, but on a device with a bad
+ // kernel this test was also useful for testing the bionic errno fix.
+ std::vector<std::thread*> threads;
+ for (size_t i = 0; i < 128; ++i) {
+ threads.push_back(new std::thread([]() {
+ ifaddrs* addrs = nullptr;
+ ASSERT_EQ(0, getifaddrs(&addrs)) << strerror(errno);
+ freeifaddrs(addrs);
+ }));
+ }
+ for (auto& t : threads) {
+ t->join();
+ delete t;
+ }
+}
+
+TEST(ifaddrs, errno_EMFILE) {
+ std::vector<int> fds;
+ while (true) {
+ int fd = open("/dev/null", O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ ASSERT_EQ(EMFILE, errno);
+ break;
+ }
+ fds.push_back(fd);
+ }
+
+ ifaddrs* addrs;
+ EXPECT_EQ(-1, getifaddrs(&addrs));
+ EXPECT_EQ(EMFILE, errno);
+
+ for (int fd : fds) close(fd);
+}