1*6dbdd20aSAndroid Build Coastguard Worker
2*6dbdd20aSAndroid Build Coastguard Worker /*
3*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
4*6dbdd20aSAndroid Build Coastguard Worker *
5*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*6dbdd20aSAndroid Build Coastguard Worker *
9*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*6dbdd20aSAndroid Build Coastguard Worker *
11*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
16*6dbdd20aSAndroid Build Coastguard Worker */
17*6dbdd20aSAndroid Build Coastguard Worker
18*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
19*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/build_config.h"
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker #include <fcntl.h>
22*6dbdd20aSAndroid Build Coastguard Worker
23*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
24*6dbdd20aSAndroid Build Coastguard Worker #include <io.h>
25*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
26*6dbdd20aSAndroid Build Coastguard Worker #include <lib/fdio/fdio.h>
27*6dbdd20aSAndroid Build Coastguard Worker #else
28*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
29*6dbdd20aSAndroid Build Coastguard Worker // Double closing of file handles on Windows leads to invocation of the invalid
30*6dbdd20aSAndroid Build Coastguard Worker // parameter handler or asserts and therefore it cannot be tested, but it can
31*6dbdd20aSAndroid Build Coastguard Worker // be tested on other platforms.
32*6dbdd20aSAndroid Build Coastguard Worker #define TEST_INVALID_CLOSE
33*6dbdd20aSAndroid Build Coastguard Worker #endif
34*6dbdd20aSAndroid Build Coastguard Worker
35*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
36*6dbdd20aSAndroid Build Coastguard Worker
37*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
38*6dbdd20aSAndroid Build Coastguard Worker namespace base {
39*6dbdd20aSAndroid Build Coastguard Worker namespace {
40*6dbdd20aSAndroid Build Coastguard Worker
OpenDevNull()41*6dbdd20aSAndroid Build Coastguard Worker int OpenDevNull() {
42*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
43*6dbdd20aSAndroid Build Coastguard Worker return fdio_fd_create_null();
44*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
45*6dbdd20aSAndroid Build Coastguard Worker return open("NUL", O_RDONLY);
46*6dbdd20aSAndroid Build Coastguard Worker #else
47*6dbdd20aSAndroid Build Coastguard Worker return open("/dev/null", O_RDONLY);
48*6dbdd20aSAndroid Build Coastguard Worker #endif
49*6dbdd20aSAndroid Build Coastguard Worker }
50*6dbdd20aSAndroid Build Coastguard Worker
OpenDevNullStream()51*6dbdd20aSAndroid Build Coastguard Worker FILE* OpenDevNullStream() {
52*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
53*6dbdd20aSAndroid Build Coastguard Worker return fdopen(fdio_fd_create_null(), "r");
54*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
55*6dbdd20aSAndroid Build Coastguard Worker return fopen("NUL", "r");
56*6dbdd20aSAndroid Build Coastguard Worker #else
57*6dbdd20aSAndroid Build Coastguard Worker return fopen("/dev/null", "r");
58*6dbdd20aSAndroid Build Coastguard Worker #endif
59*6dbdd20aSAndroid Build Coastguard Worker }
60*6dbdd20aSAndroid Build Coastguard Worker
61*6dbdd20aSAndroid Build Coastguard Worker // Returns a file descriptor to some file. On Fuchsia: returns a descriptor of a
62*6dbdd20aSAndroid Build Coastguard Worker // file in /tmp. On other platforms: returns a descriptor of /dev/zero.
MakeSecondFileDescriptor()63*6dbdd20aSAndroid Build Coastguard Worker int MakeSecondFileDescriptor() {
64*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
65*6dbdd20aSAndroid Build Coastguard Worker // Create a random file in /tmp and unlink it straight away since its name
66*6dbdd20aSAndroid Build Coastguard Worker // never need be known or uttered.
67*6dbdd20aSAndroid Build Coastguard Worker char path[] = "/tmp/sfuXXXXXX";
68*6dbdd20aSAndroid Build Coastguard Worker const int fd = mkstemp(&path[0]);
69*6dbdd20aSAndroid Build Coastguard Worker if (fd >= 0)
70*6dbdd20aSAndroid Build Coastguard Worker unlink(path);
71*6dbdd20aSAndroid Build Coastguard Worker return fd;
72*6dbdd20aSAndroid Build Coastguard Worker #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
73*6dbdd20aSAndroid Build Coastguard Worker return open("NUL", O_RDONLY);
74*6dbdd20aSAndroid Build Coastguard Worker #else
75*6dbdd20aSAndroid Build Coastguard Worker return open("/dev/zero", O_RDONLY);
76*6dbdd20aSAndroid Build Coastguard Worker #endif
77*6dbdd20aSAndroid Build Coastguard Worker }
78*6dbdd20aSAndroid Build Coastguard Worker
79*6dbdd20aSAndroid Build Coastguard Worker #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
TEST(ScopedDirTest,CloseOutOfScope)80*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedDirTest, CloseOutOfScope) {
81*6dbdd20aSAndroid Build Coastguard Worker DIR* dir_handle = opendir(".");
82*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(nullptr, dir_handle);
83*6dbdd20aSAndroid Build Coastguard Worker int dir_handle_fd = dirfd(dir_handle);
84*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(dir_handle_fd, 0);
85*6dbdd20aSAndroid Build Coastguard Worker {
86*6dbdd20aSAndroid Build Coastguard Worker ScopedDir scoped_dir(dir_handle);
87*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(dir_handle, scoped_dir.get());
88*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(scoped_dir);
89*6dbdd20aSAndroid Build Coastguard Worker }
90*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(dir_handle_fd)); // Should fail when closing twice.
91*6dbdd20aSAndroid Build Coastguard Worker }
92*6dbdd20aSAndroid Build Coastguard Worker #endif
93*6dbdd20aSAndroid Build Coastguard Worker
TEST(ScopedFileTest,CloseOutOfScope)94*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFileTest, CloseOutOfScope) {
95*6dbdd20aSAndroid Build Coastguard Worker int raw_fd = OpenDevNull();
96*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd, 0);
97*6dbdd20aSAndroid Build Coastguard Worker {
98*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file(raw_fd);
99*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd, scoped_file.get());
100*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd, *scoped_file);
101*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(scoped_file);
102*6dbdd20aSAndroid Build Coastguard Worker }
103*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
104*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd)); // Should fail when closing twice.
105*6dbdd20aSAndroid Build Coastguard Worker #endif
106*6dbdd20aSAndroid Build Coastguard Worker }
107*6dbdd20aSAndroid Build Coastguard Worker
TEST(ScopedFstreamTest,CloseOutOfScope)108*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFstreamTest, CloseOutOfScope) {
109*6dbdd20aSAndroid Build Coastguard Worker FILE* raw_stream = OpenDevNullStream();
110*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(nullptr, raw_stream);
111*6dbdd20aSAndroid Build Coastguard Worker {
112*6dbdd20aSAndroid Build Coastguard Worker ScopedFstream scoped_stream(raw_stream);
113*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_stream, scoped_stream.get());
114*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_stream, *scoped_stream);
115*6dbdd20aSAndroid Build Coastguard Worker ASSERT_TRUE(scoped_stream);
116*6dbdd20aSAndroid Build Coastguard Worker }
117*6dbdd20aSAndroid Build Coastguard Worker // We don't have a direct way to see that the file was closed.
118*6dbdd20aSAndroid Build Coastguard Worker }
119*6dbdd20aSAndroid Build Coastguard Worker
TEST(ScopedFileTest,Reset)120*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFileTest, Reset) {
121*6dbdd20aSAndroid Build Coastguard Worker int raw_fd1 = OpenDevNull();
122*6dbdd20aSAndroid Build Coastguard Worker int raw_fd2 = MakeSecondFileDescriptor();
123*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd1, 0);
124*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd2, 0);
125*6dbdd20aSAndroid Build Coastguard Worker {
126*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file(raw_fd1);
127*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd1, scoped_file.get());
128*6dbdd20aSAndroid Build Coastguard Worker scoped_file.reset(raw_fd2);
129*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd2, scoped_file.get());
130*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
131*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd1)); // Should fail when closing twice.
132*6dbdd20aSAndroid Build Coastguard Worker #endif
133*6dbdd20aSAndroid Build Coastguard Worker scoped_file.reset();
134*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
135*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd2));
136*6dbdd20aSAndroid Build Coastguard Worker #endif
137*6dbdd20aSAndroid Build Coastguard Worker scoped_file.reset(OpenDevNull());
138*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(scoped_file.get(), 0);
139*6dbdd20aSAndroid Build Coastguard Worker }
140*6dbdd20aSAndroid Build Coastguard Worker }
141*6dbdd20aSAndroid Build Coastguard Worker
TEST(ScopedFileTest,Release)142*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFileTest, Release) {
143*6dbdd20aSAndroid Build Coastguard Worker int raw_fd = OpenDevNull();
144*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd, 0);
145*6dbdd20aSAndroid Build Coastguard Worker {
146*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file(raw_fd);
147*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd, scoped_file.release());
148*6dbdd20aSAndroid Build Coastguard Worker ASSERT_FALSE(scoped_file);
149*6dbdd20aSAndroid Build Coastguard Worker }
150*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(0, close(raw_fd));
151*6dbdd20aSAndroid Build Coastguard Worker }
152*6dbdd20aSAndroid Build Coastguard Worker
TEST(ScopedFileTest,MoveCtor)153*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFileTest, MoveCtor) {
154*6dbdd20aSAndroid Build Coastguard Worker int raw_fd1 = OpenDevNull();
155*6dbdd20aSAndroid Build Coastguard Worker int raw_fd2 = MakeSecondFileDescriptor();
156*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd1, 0);
157*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd2, 0);
158*6dbdd20aSAndroid Build Coastguard Worker {
159*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file1(ScopedFile{raw_fd1});
160*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file2(std::move(scoped_file1));
161*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(-1, scoped_file1.get());
162*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(-1, *scoped_file1);
163*6dbdd20aSAndroid Build Coastguard Worker ASSERT_FALSE(scoped_file1);
164*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd1, scoped_file2.get());
165*6dbdd20aSAndroid Build Coastguard Worker
166*6dbdd20aSAndroid Build Coastguard Worker scoped_file1.reset(raw_fd2);
167*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd2, scoped_file1.get());
168*6dbdd20aSAndroid Build Coastguard Worker }
169*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
170*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd1)); // Should fail when closing twice.
171*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd2));
172*6dbdd20aSAndroid Build Coastguard Worker #endif
173*6dbdd20aSAndroid Build Coastguard Worker }
174*6dbdd20aSAndroid Build Coastguard Worker
TEST(ScopedFileTest,MoveAssignment)175*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFileTest, MoveAssignment) {
176*6dbdd20aSAndroid Build Coastguard Worker int raw_fd1 = OpenDevNull();
177*6dbdd20aSAndroid Build Coastguard Worker int raw_fd2 = MakeSecondFileDescriptor();
178*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd1, 0);
179*6dbdd20aSAndroid Build Coastguard Worker ASSERT_GE(raw_fd2, 0);
180*6dbdd20aSAndroid Build Coastguard Worker {
181*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file1(raw_fd1);
182*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file2(raw_fd2);
183*6dbdd20aSAndroid Build Coastguard Worker scoped_file2 = std::move(scoped_file1);
184*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(-1, scoped_file1.get());
185*6dbdd20aSAndroid Build Coastguard Worker ASSERT_FALSE(scoped_file1);
186*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd1, scoped_file2.get());
187*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
188*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd2));
189*6dbdd20aSAndroid Build Coastguard Worker #endif
190*6dbdd20aSAndroid Build Coastguard Worker
191*6dbdd20aSAndroid Build Coastguard Worker scoped_file1 = std::move(scoped_file2);
192*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(raw_fd1, scoped_file1.get());
193*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(-1, scoped_file2.get());
194*6dbdd20aSAndroid Build Coastguard Worker }
195*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
196*6dbdd20aSAndroid Build Coastguard Worker ASSERT_NE(0, close(raw_fd1));
197*6dbdd20aSAndroid Build Coastguard Worker #endif
198*6dbdd20aSAndroid Build Coastguard Worker }
199*6dbdd20aSAndroid Build Coastguard Worker
200*6dbdd20aSAndroid Build Coastguard Worker // File descriptors are capabilities and hence can be security critical. A
201*6dbdd20aSAndroid Build Coastguard Worker // failed close() suggests the memory ownership of the file is wrong and we
202*6dbdd20aSAndroid Build Coastguard Worker // might have leaked a capability.
203*6dbdd20aSAndroid Build Coastguard Worker #ifdef TEST_INVALID_CLOSE
TEST(ScopedFileTest,CloseFailureIsFatal)204*6dbdd20aSAndroid Build Coastguard Worker TEST(ScopedFileTest, CloseFailureIsFatal) {
205*6dbdd20aSAndroid Build Coastguard Worker int raw_fd = OpenDevNull();
206*6dbdd20aSAndroid Build Coastguard Worker ASSERT_DEATH_IF_SUPPORTED(
207*6dbdd20aSAndroid Build Coastguard Worker {
208*6dbdd20aSAndroid Build Coastguard Worker ScopedFile scoped_file(raw_fd);
209*6dbdd20aSAndroid Build Coastguard Worker ASSERT_EQ(0, close(raw_fd));
210*6dbdd20aSAndroid Build Coastguard Worker },
211*6dbdd20aSAndroid Build Coastguard Worker "");
212*6dbdd20aSAndroid Build Coastguard Worker }
213*6dbdd20aSAndroid Build Coastguard Worker #endif
214*6dbdd20aSAndroid Build Coastguard Worker
215*6dbdd20aSAndroid Build Coastguard Worker } // namespace
216*6dbdd20aSAndroid Build Coastguard Worker } // namespace base
217*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
218