Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2017 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 "perfetto/base/scoped_file.h"
     18 
     19 #include <fcntl.h>
     20 #include <unistd.h>
     21 
     22 #include "gtest/gtest.h"
     23 
     24 namespace perfetto {
     25 namespace base {
     26 namespace {
     27 
     28 TEST(ScopedDirTest, CloseOutOfScope) {
     29   DIR* dir_handle = opendir(".");
     30   ASSERT_NE(nullptr, dir_handle);
     31   int dir_handle_fd = dirfd(dir_handle);
     32   ASSERT_GE(dir_handle_fd, 0);
     33   {
     34     ScopedDir scoped_dir(dir_handle);
     35     ASSERT_EQ(dir_handle, scoped_dir.get());
     36     ASSERT_TRUE(scoped_dir);
     37   }
     38   ASSERT_NE(0, close(dir_handle_fd));  // Should fail when closing twice.
     39 }
     40 
     41 TEST(ScopedFileTest, CloseOutOfScope) {
     42   int raw_fd = open("/dev/null", O_RDONLY);
     43   ASSERT_GE(raw_fd, 0);
     44   {
     45     ScopedFile scoped_file(raw_fd);
     46     ASSERT_EQ(raw_fd, scoped_file.get());
     47     ASSERT_EQ(raw_fd, *scoped_file);
     48     ASSERT_TRUE(scoped_file);
     49   }
     50   ASSERT_NE(0, close(raw_fd));  // Should fail when closing twice.
     51 }
     52 
     53 TEST(ScopedFstreamTest, CloseOutOfScope) {
     54   FILE* raw_stream = fopen("/dev/null", "r");
     55   ASSERT_NE(nullptr, raw_stream);
     56   {
     57     ScopedFstream scoped_stream(raw_stream);
     58     ASSERT_EQ(raw_stream, scoped_stream.get());
     59     ASSERT_EQ(raw_stream, *scoped_stream);
     60     ASSERT_TRUE(scoped_stream);
     61   }
     62   // We don't have a direct way to see that the file was closed.
     63 }
     64 
     65 TEST(ScopedFileTest, Reset) {
     66   int raw_fd1 = open("/dev/null", O_RDONLY);
     67   int raw_fd2 = open("/dev/zero", O_RDONLY);
     68   ASSERT_GE(raw_fd1, 0);
     69   ASSERT_GE(raw_fd2, 0);
     70   {
     71     ScopedFile scoped_file(raw_fd1);
     72     ASSERT_EQ(raw_fd1, scoped_file.get());
     73     scoped_file.reset(raw_fd2);
     74     ASSERT_EQ(raw_fd2, scoped_file.get());
     75     ASSERT_NE(0, close(raw_fd1));  // Should fail when closing twice.
     76     scoped_file.reset();
     77     ASSERT_NE(0, close(raw_fd2));
     78     scoped_file.reset(open("/dev/null", O_RDONLY));
     79     ASSERT_GE(scoped_file.get(), 0);
     80   }
     81 }
     82 
     83 TEST(ScopedFileTest, Release) {
     84   int raw_fd = open("/dev/null", O_RDONLY);
     85   ASSERT_GE(raw_fd, 0);
     86   {
     87     ScopedFile scoped_file(raw_fd);
     88     ASSERT_EQ(raw_fd, scoped_file.release());
     89     ASSERT_FALSE(scoped_file);
     90   }
     91   ASSERT_EQ(0, close(raw_fd));
     92 }
     93 
     94 TEST(ScopedFileTest, MoveCtor) {
     95   int raw_fd1 = open("/dev/null", O_RDONLY);
     96   int raw_fd2 = open("/dev/zero", O_RDONLY);
     97   ASSERT_GE(raw_fd1, 0);
     98   ASSERT_GE(raw_fd2, 0);
     99   {
    100     ScopedFile scoped_file1(ScopedFile{raw_fd1});
    101     ScopedFile scoped_file2(std::move(scoped_file1));
    102     ASSERT_EQ(-1, scoped_file1.get());
    103     ASSERT_EQ(-1, *scoped_file1);
    104     ASSERT_FALSE(scoped_file1);
    105     ASSERT_EQ(raw_fd1, scoped_file2.get());
    106 
    107     scoped_file1.reset(raw_fd2);
    108     ASSERT_EQ(raw_fd2, scoped_file1.get());
    109   }
    110   ASSERT_NE(0, close(raw_fd1));  // Should fail when closing twice.
    111   ASSERT_NE(0, close(raw_fd2));
    112 }
    113 
    114 TEST(ScopedFileTest, MoveAssignment) {
    115   int raw_fd1 = open("/dev/null", O_RDONLY);
    116   int raw_fd2 = open("/dev/zero", O_RDONLY);
    117   ASSERT_GE(raw_fd1, 0);
    118   ASSERT_GE(raw_fd2, 0);
    119   {
    120     ScopedFile scoped_file1(raw_fd1);
    121     ScopedFile scoped_file2(raw_fd2);
    122     scoped_file2 = std::move(scoped_file1);
    123     ASSERT_EQ(-1, scoped_file1.get());
    124     ASSERT_FALSE(scoped_file1);
    125     ASSERT_EQ(raw_fd1, scoped_file2.get());
    126     ASSERT_NE(0, close(raw_fd2));
    127 
    128     scoped_file1 = std::move(scoped_file2);
    129     ASSERT_EQ(raw_fd1, scoped_file1.get());
    130     ASSERT_EQ(-1, scoped_file2.get());
    131   }
    132   ASSERT_NE(0, close(raw_fd1));
    133 }
    134 
    135 // File descriptors are capabilities and hence can be security critical. A
    136 // failed close() suggests the memory ownership of the file is wrong and we
    137 // might have leaked a capability.
    138 TEST(ScopedFileTest, CloseFailureIsFatal) {
    139   int raw_fd = open("/dev/null", O_RDONLY);
    140   ASSERT_DEATH(
    141       {
    142         ScopedFile scoped_file(raw_fd);
    143         ASSERT_EQ(0, close(raw_fd));
    144       },
    145       "");
    146 }
    147 
    148 }  // namespace
    149 }  // namespace base
    150 }  // namespace perfetto
    151