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