summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorJosh Gao2018-05-31 23:24:14 -0500
committerJosh Gao2018-07-18 20:11:46 -0500
commitfcf2c01b5599a96b968afb1528c996d9486937b0 (patch)
tree623c9e7d59c96d047258e72f304104c669817af4 /base
parent54f40303d5632e7f5852cd9f467454281c4f979a (diff)
downloadplatform-system-core-fcf2c01b5599a96b968afb1528c996d9486937b0.tar.gz
platform-system-core-fcf2c01b5599a96b968afb1528c996d9486937b0.tar.xz
platform-system-core-fcf2c01b5599a96b968afb1528c996d9486937b0.zip
base: add support for tagged fd closure to unique_fd.
Test: libbase_test Change-Id: Ibba5e60d7007265a566eb8f76021d5dbeb734532
Diffstat (limited to 'base')
-rw-r--r--base/Android.bp1
-rw-r--r--base/include/android-base/unique_fd.h82
-rw-r--r--base/unique_fd_test.cpp54
3 files changed, 123 insertions, 14 deletions
diff --git a/base/Android.bp b/base/Android.bp
index 3d80d9719..46a023342 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -135,6 +135,7 @@ cc_test {
135 "strings_test.cpp", 135 "strings_test.cpp",
136 "test_main.cpp", 136 "test_main.cpp",
137 "test_utils_test.cpp", 137 "test_utils_test.cpp",
138 "unique_fd_test.cpp",
138 ], 139 ],
139 target: { 140 target: {
140 android: { 141 android: {
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 6cfcd3fb0..057f462e5 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -42,10 +42,29 @@
42// 42//
43// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help 43// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
44// you find this class if you're searching for one of those names. 44// you find this class if you're searching for one of those names.
45
46#if defined(__BIONIC__)
47#include <android/fdsan.h>
48#endif
49
45namespace android { 50namespace android {
46namespace base { 51namespace base {
47 52
48struct DefaultCloser { 53struct DefaultCloser {
54#if defined(__BIONIC__)
55 static void Tag(int fd, void* old_addr, void* new_addr) {
56 uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
57 reinterpret_cast<uint64_t>(old_addr));
58 uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
59 reinterpret_cast<uint64_t>(new_addr));
60 android_fdsan_exchange_owner_tag(fd, old_tag, new_tag);
61 }
62 static void Close(int fd, void* addr) {
63 uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD,
64 reinterpret_cast<uint64_t>(addr));
65 android_fdsan_close_with_tag(fd, tag);
66 }
67#else
49 static void Close(int fd) { 68 static void Close(int fd) {
50 // Even if close(2) fails with EINTR, the fd will have been closed. 69 // Even if close(2) fails with EINTR, the fd will have been closed.
51 // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone 70 // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
@@ -53,40 +72,75 @@ struct DefaultCloser {
53 // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html 72 // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
54 ::close(fd); 73 ::close(fd);
55 } 74 }
75#endif
56}; 76};
57 77
58template <typename Closer> 78template <typename Closer>
59class unique_fd_impl final { 79class unique_fd_impl final {
60 public: 80 public:
61 unique_fd_impl() : value_(-1) {} 81 unique_fd_impl() {}
62 82
63 explicit unique_fd_impl(int value) : value_(value) {} 83 explicit unique_fd_impl(int fd) { reset(fd); }
64 ~unique_fd_impl() { reset(); } 84 ~unique_fd_impl() { reset(); }
65 85
66 unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {} 86 unique_fd_impl(unique_fd_impl&& other) { reset(other.release()); }
67 unique_fd_impl& operator=(unique_fd_impl&& s) { 87 unique_fd_impl& operator=(unique_fd_impl&& s) {
68 reset(s.release()); 88 int fd = s.fd_;
89 s.fd_ = -1;
90 reset(fd, &s);
69 return *this; 91 return *this;
70 } 92 }
71 93
72 void reset(int new_value = -1) { 94 void reset(int new_value = -1) { reset(new_value, nullptr); }
73 if (value_ != -1) {
74 Closer::Close(value_);
75 }
76 value_ = new_value;
77 }
78 95
79 int get() const { return value_; } 96 int get() const { return fd_; }
80 operator int() const { return get(); } 97 operator int() const { return get(); }
81 98
82 int release() __attribute__((warn_unused_result)) { 99 int release() __attribute__((warn_unused_result)) {
83 int ret = value_; 100 tag(fd_, this, nullptr);
84 value_ = -1; 101 int ret = fd_;
102 fd_ = -1;
85 return ret; 103 return ret;
86 } 104 }
87 105
88 private: 106 private:
89 int value_; 107 void reset(int new_value, void* previous_tag) {
108 if (fd_ != -1) {
109 close(fd_, this);
110 }
111
112 fd_ = new_value;
113 if (new_value != -1) {
114 tag(new_value, previous_tag, this);
115 }
116 }
117
118 int fd_ = -1;
119
120 // Template magic to use Closer::Tag if available, and do nothing if not.
121 // If Closer::Tag exists, this implementation is preferred, because int is a better match.
122 // If not, this implementation is SFINAEd away, and the no-op below is the only one that exists.
123 template <typename T = Closer>
124 static auto tag(int fd, void* old_tag, void* new_tag)
125 -> decltype(T::Tag(fd, old_tag, new_tag), void()) {
126 T::Tag(fd, old_tag, new_tag);
127 }
128
129 template <typename T = Closer>
130 static void tag(long, void*, void*) {
131 // No-op.
132 }
133
134 // Same as above, to select between Closer::Close(int) and Closer::Close(int, void*).
135 template <typename T = Closer>
136 static auto close(int fd, void* tag_value) -> decltype(T::Close(fd, tag_value), void()) {
137 T::Close(fd, tag_value);
138 }
139
140 template <typename T = Closer>
141 static auto close(int fd, void*) -> decltype(T::Close(fd), void()) {
142 T::Close(fd);
143 }
90 144
91 unique_fd_impl(const unique_fd_impl&); 145 unique_fd_impl(const unique_fd_impl&);
92 void operator=(const unique_fd_impl&); 146 void operator=(const unique_fd_impl&);
diff --git a/base/unique_fd_test.cpp b/base/unique_fd_test.cpp
new file mode 100644
index 000000000..3fdf12a30
--- /dev/null
+++ b/base/unique_fd_test.cpp
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "android-base/unique_fd.h"
18
19#include <gtest/gtest.h>
20
21#include <errno.h>
22#include <fcntl.h>
23#include <unistd.h>
24
25using android::base::unique_fd;
26
27TEST(unique_fd, unowned_close) {
28#if defined(__BIONIC__)
29 unique_fd fd(open("/dev/null", O_RDONLY));
30 EXPECT_DEATH(close(fd.get()), "incorrect tag");
31#endif
32}
33
34TEST(unique_fd, untag_on_release) {
35 unique_fd fd(open("/dev/null", O_RDONLY));
36 close(fd.release());
37}
38
39TEST(unique_fd, move) {
40 unique_fd fd(open("/dev/null", O_RDONLY));
41 unique_fd fd_moved = std::move(fd);
42 ASSERT_EQ(-1, fd.get());
43 ASSERT_GT(fd_moved.get(), -1);
44}
45
46TEST(unique_fd, unowned_close_after_move) {
47#if defined(__BIONIC__)
48 unique_fd fd(open("/dev/null", O_RDONLY));
49 unique_fd fd_moved = std::move(fd);
50 ASSERT_EQ(-1, fd.get());
51 ASSERT_GT(fd_moved.get(), -1);
52 EXPECT_DEATH(close(fd_moved.get()), "incorrect tag");
53#endif
54}