From 344c5f2a6247931f48b217ff19a9aaec65af57f3 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sat, 2 Apr 2022 22:14:31 +0530 Subject: [PATCH] Implement RAII wrapper over file descriptors The `FileDescriptor` class is a RAII wrapper over FDs which handles their lifetimes alongside other C++ semantics such as moving and copying. It has been used in `skyline::kernel::MemoryManager` to handle the lifetime of the ashmem FD correctly, it wasn't being destroyed earlier which can result in leaking FDs across runs. --- .../main/cpp/skyline/common/file_descriptor.h | 69 +++++++++++++++++++ app/src/main/cpp/skyline/kernel/memory.h | 5 +- 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 app/src/main/cpp/skyline/common/file_descriptor.h diff --git a/app/src/main/cpp/skyline/common/file_descriptor.h b/app/src/main/cpp/skyline/common/file_descriptor.h new file mode 100644 index 00000000..0301ad0e --- /dev/null +++ b/app/src/main/cpp/skyline/common/file_descriptor.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include "base.h" + +namespace skyline { + /** + * @brief A RAII wrapper around Linux file descriptors which automatically closes the file descriptor when it goes out of scope and duplicates them on copies + * @note This class should **always** be moved rather than copied where possible to avoid a system call for duplicating file descriptors + */ + class FileDescriptor { + private: + int fd; + + public: + FileDescriptor() : fd(-1) {} + + FileDescriptor(int fd) : fd(fd) {} + + FileDescriptor &operator=(int newFd) { + if (fd != -1) + close(fd); + fd = newFd; + return *this; + } + + FileDescriptor(const FileDescriptor &other) : fd(dup(other.fd)) { + if (fd == -1) + throw exception("Failed to duplicate file descriptor: {}", strerror(errno)); + } + + FileDescriptor &operator=(const FileDescriptor &other) { + if (fd != -1) + close(fd); + fd = dup(other.fd); + if (fd == -1) + throw exception("Failed to duplicate file descriptor: {}", strerror(errno)); + return *this; + } + + FileDescriptor(FileDescriptor &&other) : fd(other.fd) { + other.fd = -1; + } + + FileDescriptor &operator=(FileDescriptor &&other) { + if (fd != -1) + close(fd); + fd = other.fd; + other.fd = -1; + return *this; + } + + ~FileDescriptor() { + if (fd != -1) + close(fd); + } + + operator int() const { + return fd; + } + + int operator*() const { + return fd; + } + }; +} diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 5231ad58..b344d05e 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -3,8 +3,9 @@ #pragma once -#include #include +#include +#include namespace skyline { namespace memory { @@ -226,7 +227,7 @@ namespace skyline { memory::Region stack{}; memory::Region tlsIo{}; //!< TLS/IO - int memoryFd{}; //!< The file descriptor of the memory backing for the entire guest address space + FileDescriptor memoryFd{}; //!< The file descriptor of the memory backing for the entire guest address space std::shared_mutex mutex; //!< Synchronizes any operations done on the VMM, it's locked in shared mode by readers and exclusive mode by writers