From a61421621c194a25779a870bf07a2d155198019f Mon Sep 17 00:00:00 2001 From: Federico Stazi Date: Fri, 25 Sep 2020 15:06:24 +0000 Subject: [PATCH] Address review comments --- oss-internship-2020/libuv/CMakeLists.txt | 48 ++++---- oss-internship-2020/libuv/README.md | 63 +++++++--- .../libuv/callbacks/callbacks.cc | 51 ++++---- .../libuv/callbacks/callbacks.h | 21 ++-- oss-internship-2020/libuv/examples/README.md | 22 +++- .../libuv/examples/helloworld.cc | 62 +++++----- .../libuv/examples/idle-basic.cc | 94 +++++++-------- oss-internship-2020/libuv/examples/uvcat.cc | 112 ++++++++---------- .../libuv/generator/wrapper_generator.py | 93 ++++++++------- oss-internship-2020/libuv/tests/test_array.cc | 12 +- .../libuv/tests/test_callback.cc | 12 +- oss-internship-2020/libuv/tests/test_error.cc | 12 +- oss-internship-2020/libuv/tests/test_loop.cc | 12 +- oss-internship-2020/libuv/tests/test_os.cc | 12 +- 14 files changed, 333 insertions(+), 293 deletions(-) diff --git a/oss-internship-2020/libuv/CMakeLists.txt b/oss-internship-2020/libuv/CMakeLists.txt index 06a0107..6ffe8b6 100644 --- a/oss-internship-2020/libuv/CMakeLists.txt +++ b/oss-internship-2020/libuv/CMakeLists.txt @@ -1,4 +1,3 @@ - # Copyright 2020 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,13 +12,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.12) project(libuv_sandbox) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) +# Add SAPI directories +add_subdirectory( + "${SAPI_ROOT}" + "${CMAKE_BINARY_DIR}/sandboxed-api-build" + EXCLUDE_FROM_ALL +) + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/uv_wrapper") add_custom_command( @@ -28,33 +34,33 @@ add_custom_command( WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMAND python3 "generator/wrapper_generator.py" - "libuv/include/uv.h" - "${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h" - "${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc" + COMMAND "${SAPI_PYTHON3_EXECUTABLE}" + "generator/wrapper_generator.py" + "libuv/include/uv.h" + "${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h" + "${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc" COMMENT "Generate the wrapper header and source files" - ) -option(UV_SAPI_ENABLE_EXAMPLES "" ON) -option(UV_SAPI_ENABLE_TESTS "" ON) +option(SAPI_UV_ENABLE_EXAMPLES "" ON) +option(SAPI_UV_ENABLE_TESTS "" ON) # Add callbacks used by examples and tests -if (UV_SAPI_ENABLE_EXAMPLES OR UV_SAPI_ENABLE_TESTS) - list(APPEND UV_SAPI_CALLBACKS +if (SAPI_UV_ENABLE_EXAMPLES OR SAPI_UV_ENABLE_TESTS) + list(APPEND SAPI_UV_CALLBACKS "${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.h" "${CMAKE_CURRENT_SOURCE_DIR}/callbacks/callbacks.cc" ) endif() # Wrapper library including wrappers for all libuv methods and callbacks -# The UV_SAPI_CALLBACKS variable should contain the absolute paths of +# The SAPI_UV_CALLBACKS variable should contain the absolute paths of # all the files implementing the callbacks add_library(uv_wrapper_and_callbacks OBJECT "${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.h" "${CMAKE_BINARY_DIR}/uv_wrapper/uv_wrapper.cc" - "${UV_SAPI_CALLBACKS}" + "${SAPI_UV_CALLBACKS}" ) set_target_properties(uv_wrapper_and_callbacks PROPERTIES LINKER_LANGUAGE C @@ -66,13 +72,8 @@ target_link_libraries(uv_wrapper_and_callbacks uv_a) # Setup Sandboxed API set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") -set(SAPI_ENABLE_EXAMPLES ${UV_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE) -set(SAPI_ENABLE_TESTS ${UV_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE) -add_subdirectory( - "${SAPI_ROOT}" - "${CMAKE_BINARY_DIR}/sandboxed-api-build" - EXCLUDE_FROM_ALL -) +set(SAPI_ENABLE_EXAMPLES ${SAPI_UV_ENABLE_EXAMPLES} CACHE BOOL "" FORCE) +set(SAPI_ENABLE_TESTS ${SAPI_UV_ENABLE_TESTS} CACHE BOOL "" FORCE) # Generate SAPI header add_sapi_library(uv_sapi @@ -374,8 +375,7 @@ add_sapi_library(uv_sapi LIBRARY_NAME UV - NAMESPACE "" - + NAMESPACE uv ) # Include generated SAPI header @@ -384,11 +384,11 @@ target_include_directories(uv_sapi INTERFACE ) # Add examples -if (UV_SAPI_ENABLE_EXAMPLES) +if (SAPI_UV_ENABLE_EXAMPLES) add_subdirectory(examples) endif() # Add tests -if (UV_SAPI_ENABLE_TESTS) +if (SAPI_UV_ENABLE_TESTS) add_subdirectory(tests) endif() diff --git a/oss-internship-2020/libuv/README.md b/oss-internship-2020/libuv/README.md index bc49e80..0e1cb76 100644 --- a/oss-internship-2020/libuv/README.md +++ b/oss-internship-2020/libuv/README.md @@ -1,6 +1,7 @@ # LibUV Sandbox -This library is a sandboxed version of [LibUV](https://libuv.org/), implemented using Sandboxed API. +This library is a sandboxed version of [LibUV](https://libuv.org/), implemented +using Sandboxed API. ## Setup @@ -8,16 +9,19 @@ The repository can be cloned using: ``` git clone --recursive [URL to this repo] ``` -The `--recursive` flag ensures that submodules are also cloned. +The `--recursive` flag ensures that submodules are also cloned. -Alternatively, if the repository has already been cloned but the submodules have not, these can be cloned using: +Alternatively, if the repository has already been cloned but the submodules have +not, these can be cloned using: ``` git submodule update --init --recursive -``` +``` -The full list of Sandboxed API dependencies can be found on [Sandboxed API Getting Started page](https://developers.google.com/sandboxed-api/docs/getting-started). +The full list of Sandboxed API dependencies can be found on +[Sandboxed API Getting Started page](https://developers.google.com/sandboxed-api/docs/getting-started). -The following commands, used from the current `libuv/` directory, build the library: +The following commands, used from the current `libuv/` directory, build the +library: ``` mkdir -p build cd build @@ -27,36 +31,63 @@ cmake --build . ## Implementation details -LibUV can't be directly sandboxed by Sandboxed API. Because of the size and complexity of the library, doing so creates some compilation errors and does not create the correct APIs for all methods. The solution for this issue is creating a wrapper library, whose methods (which can be sandboxed properly) internally call the original LibUV's methods. +LibUV can't be directly sandboxed by Sandboxed API. Because of the size and +complexity of the library, doing so creates some compilation errors and does not +create the correct APIs for all methods. The solution for this issue is creating +a wrapper library, whose methods (which can be sandboxed properly) internally +call the original LibUV's methods. -Using these wrapper methods is extremely simple, the only relevant difference is that they have a `sapi_` prefix before their names (e.g. `uv_loop_init` becomes `sapi_uv_loop_init`). The only exception is the variadic method `uv_loop_configure`. This has two wrappers, `sapi_uv_loop_configure` (with no additional parameters) and `sapi_uv_loop_configure_int` (with an additional `int` parameter). Currently, these are the only valid calls to the method in LibUV. +Using these wrapper methods is extremely simple, the only relevant difference is +that they have a `sapi_` prefix before their names (e.g. `uv_loop_init` becomes +`sapi_uv_loop_init`). The only exception is the variadic method +`uv_loop_configure`. This has two wrappers, `sapi_uv_loop_configure` (with no +additional parameters) and `sapi_uv_loop_configure_int` (with an additional +`int` parameter). Currently, these are the only valid calls to the method in +LibUV. #### Wrapper generator -The wrapper is generated automatically by a Python script that is called by CMake at build time. This script can be found in the `generator` folder. +The wrapper is generated automatically by a Python script that is called by +CMake at build time. This script can be found in the `generator` folder. #### Function pointers -The functions whose pointers will be passed to the library's methods (*callbacks*) can't be implemented in the files making use of the library, but must be in other files. These files must be compiled together with the library, and this is done by adding their absolute path to the CMake variable `UV_SAPI_CALLBACKS`. +The functions whose pointers will be passed to the library's methods +(*callbacks*) can't be implemented in the files making use of the library, but +must be in other files. These files must be compiled together with the library, +and this is done by adding their absolute path to the CMake variable +`SAPI_UV_CALLBACKS`. -The pointers can then be obtained using an `RPCChannel` object, as shown in the example `idle-basic.cc`. +The pointers can then be obtained using an `RPCChannel` object, as shown in the +example `idle-basic.cc`. ## Examples -The `examples` directory contains the sandboxed versions of example source codes taken from from [LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). More information about each example can be found in the examples' [README](examples/README.md). +The `examples` directory contains the sandboxed versions of example source codes +taken from from [LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). +More information about each example can be found in the examples' +[README](examples/README.md). -To build these examples when building the library, the CMake variable `UV_SAPI_ENABLE_EXAMPLES` must be set to `ON`. This enables Sandboxed API examples as well. +To build these examples when building the library, the CMake variable +`SAPI_UV_ENABLE_EXAMPLES` must be set to `ON`. This enables Sandboxed API +examples as well. ## Testing The `tests` folder contains some test cases created using Google Test. -To build these tests when building the library, the CMake variable `UV_SAPI_ENABLE_TESTS` must be set to `ON`. This enables Sandboxed API tests as well. +To build these tests when building the library, the CMake variable +`SAPI_UV_ENABLE_TESTS` must be set to `ON`. This enables Sandboxed API tests as +well. ## Policies -Each example and test has an ad-hoc policy implemented on its own file. These policies can be used as references for pieces of code that perform similar operations. For example, the `helloworld.cc` example has a policy that only allows the strictly necessary syscalls for running a loop. +Each example and test has an ad-hoc policy implemented on its own file. These +policies can be used as references for pieces of code that perform similar +operations. For example, the `helloworld.cc` example has a policy that only +allows the strictly necessary syscalls for running a loop. ## Callbacks -The `callbacks.h` and `callbacks.cc` files in the `callbacks` folder implement all the callbacks used by examples and tests. +The `callbacks.h` and `callbacks.cc` files in the `callbacks` folder implement +all the callbacks used by examples and tests. diff --git a/oss-internship-2020/libuv/callbacks/callbacks.cc b/oss-internship-2020/libuv/callbacks/callbacks.cc index e89861d..3713f04 100644 --- a/oss-internship-2020/libuv/callbacks/callbacks.cc +++ b/oss-internship-2020/libuv/callbacks/callbacks.cc @@ -12,38 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "callbacks.h" +#include "callbacks.h" // NOLINT(build/include) #include -size_t iterations = 0; +size_t g_iterations = 0; size_t constexpr kMaxIterations = 1'000'000; +static char g_buffer[1024]; +static uv_buf_t g_iov; // Stop the handle if the methods was called kMaxIterations times void IdleCallback(uv_idle_t* handle) { - iterations++; - if (iterations > kMaxIterations) { + ++g_iterations; + if (g_iterations > kMaxIterations) { std::cout << "IdleCallback was called " << kMaxIterations << " times" << std::endl; uv_idle_stop(handle); } } -static char buffer[1024]; -static uv_buf_t iov; - // Called after some chars have been written // As soon as writing of these bytes is completed, read more void OnWrite(uv_fs_t* req) { if (req->result < 0) { std::cerr << "Write error: " << uv_strerror(static_cast(req->result)) << std::endl; - - } else { - // Start reading more after writing these bytes - uv_fs_read(uv_default_loop(), &read_req, open_req.result, &iov, 1, -1, - OnRead); + return; } + // Start reading more after writing these bytes + uv_fs_read(uv_default_loop(), &read_req, open_req.result, &g_iov, 1, -1, + OnRead); } // Called after some chars have been read @@ -51,16 +49,16 @@ void OnWrite(uv_fs_t* req) { void OnRead(uv_fs_t* req) { if (req->result < 0) { std::cerr << "Read error: " << uv_strerror(req->result) << std::endl; - - } else if (req->result == 0) { + return; + } + if (req->result == 0) { // No more bytes left, close the loop uv_fs_t close_req; uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); - } else if (req->result > 0) { // Start writing after reading some bytes - iov.len = req->result; - uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, OnWrite); + g_iov.len = req->result; + uv_fs_write(uv_default_loop(), &write_req, 1, &g_iov, 1, -1, OnWrite); } } @@ -69,18 +67,17 @@ void OnRead(uv_fs_t* req) { void OnOpen(uv_fs_t* req) { if (req != &open_req) { std::cerr << "Open error: req != &open_req" << std::endl; - - } else if (req->result < 0) { + return; + } + if (req->result < 0) { std::cerr << "Open error: " << uv_strerror(static_cast(req->result)) << std::endl; - - } else { - // Initialize uv_buf_t buffer - iov = uv_buf_init(buffer, sizeof(buffer)); - - // Start reading after opening - uv_fs_read(uv_default_loop(), &read_req, req->result, &iov, 1, -1, OnRead); + return; } + // Initialize uv_buf_t g_buffer + g_iov = uv_buf_init(g_buffer, sizeof(g_buffer)); + // Start reading after opening + uv_fs_read(uv_default_loop(), &read_req, req->result, &g_iov, 1, -1, OnRead); } // Get the integer pointed by handle->data and increment it by one @@ -88,6 +85,6 @@ void OnOpen(uv_fs_t* req) { void TimerCallback(uv_timer_t* handle) { int* data = static_cast( uv_handle_get_data(reinterpret_cast(handle))); - (*data)++; + ++(*data); uv_close(reinterpret_cast(handle), nullptr); } diff --git a/oss-internship-2020/libuv/callbacks/callbacks.h b/oss-internship-2020/libuv/callbacks/callbacks.h index e9acaad..560d245 100644 --- a/oss-internship-2020/libuv/callbacks/callbacks.h +++ b/oss-internship-2020/libuv/callbacks/callbacks.h @@ -12,30 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CALLBACKS_H -#define CALLBACKS_H +#ifndef CALLBACKS_H_ +#define CALLBACKS_H_ #include extern "C" { // idle-basic - -void IdleCallback(uv_idle_t *handle); +void IdleCallback(uv_idle_t* handle); // uvcat - uv_fs_t open_req; uv_fs_t read_req; uv_fs_t write_req; - -void OnWrite(uv_fs_t *req); -void OnRead(uv_fs_t *req); -void OnOpen(uv_fs_t *req); +void OnWrite(uv_fs_t* req); +void OnRead(uv_fs_t* req); +void OnOpen(uv_fs_t* req); // test_callback +void TimerCallback(uv_timer_t* handle); -void TimerCallback(uv_timer_t *handle); -} +} // extern "C" -#endif // CALLBACKS_H +#endif // CALLBACKS_H_ diff --git a/oss-internship-2020/libuv/examples/README.md b/oss-internship-2020/libuv/examples/README.md index 730c783..ec274f9 100644 --- a/oss-internship-2020/libuv/examples/README.md +++ b/oss-internship-2020/libuv/examples/README.md @@ -1,9 +1,23 @@ # LibUV Sandbox Examples -Each example in this folder is the sandboxed version of a code snippet from [LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). These examples perform some basic tasks using LibUV, and can be useful both to understand how to use LibUV Sandbox, but also to get an idea of how regular and sandboxed code compare to each other. +Each example in this folder is the sandboxed version of a code snippet from +[LibUV's User Guide](https://docs.libuv.org/en/v1.x/guide.html). These examples +perform some basic tasks using LibUV, and can be useful both to understand how +to use LibUV Sandbox, but also to get an idea of how regular and sandboxed code +compare to each other. This is the list of examples: -- **helloworld.cc**: sandboxed version of [helloworld/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#hello-world). It simply starts a loop that exits immediately. It shows how to run a simple loop in LibUV Sandbox. -- **idle-basic.cc**: sandboxed version of [idle-basic/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#handles-and-requests). Creates an idle watcher that stops the loop after a certain number of iterations. It shows how a simple callback can be used in LibUV Sandbox. -- **uvcat.cc**: sandboxed version of [uvcat/main.c](http://docs.libuv.org/en/v1.x/guide/filesystem.html#reading-writing-files). Takes a single argument, the absolute path of a file, and prints its contents (it is a simplified version of the command line tootl `cat`). It shows how to manage various complex callbacks for opening, reading and writing files. \ No newline at end of file +- **helloworld.cc**: sandboxed version of +[helloworld/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#hello-world). +It simply starts a loop that exits immediately. It shows how to run a simple +loop in LibUV Sandbox. +- **idle-basic.cc**: sandboxed version of +[idle-basic/main.c](https://docs.libuv.org/en/v1.x/guide/basics.html#handles-and-requests). +Creates an idle watcher that stops the loop after a certain number of +iterations. It shows how a simple callback can be used in LibUV Sandbox. +- **uvcat.cc**: sandboxed version of +[uvcat/main.c](http://docs.libuv.org/en/v1.x/guide/filesystem.html#reading-writing-files). +Takes a single argument, the absolute path of a file, and prints its contents +(it is a simplified version of the command line tootl `cat`). It shows how to +manage various complex callbacks for opening, reading and writing files. diff --git a/oss-internship-2020/libuv/examples/helloworld.cc b/oss-internship-2020/libuv/examples/helloworld.cc index ef5941b..1974758 100644 --- a/oss-internship-2020/libuv/examples/helloworld.cc +++ b/oss-internship-2020/libuv/examples/helloworld.cc @@ -21,7 +21,7 @@ #include "sandboxed_api/util/flag.h" #include "uv_sapi.sapi.h" -class UVSapiHelloworldSandbox : public UVSandbox { +class UVSapiHelloworldSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -35,57 +35,51 @@ class UVSapiHelloworldSandbox : public UVSandbox { } }; -int main(int argc, char* argv[]) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - - absl::Status status; - +absl::Status HelloWorld() { // Initialize sandbox2 and sapi UVSapiHelloworldSandbox sandbox; - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - UVApi api(&sandbox); + SAPI_RETURN_IF_ERROR(sandbox.Init()); + uv::UVApi api(&sandbox); // Allocate memory for the uv_loop_t object void* loop_voidptr; - status = sandbox.rpc_channel()->Allocate(sizeof(uv_loop_t), &loop_voidptr); - if (!status.ok()) { - LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Allocate failed: " << status; - } + SAPI_RETURN_IF_ERROR( + sandbox.rpc_channel()->Allocate(sizeof(uv_loop_t), &loop_voidptr)); sapi::v::RemotePtr loop(loop_voidptr); - absl::StatusOr return_code; + int return_code; // Initialize loop - return_code = api.sapi_uv_loop_init(&loop); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_loop_init failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "uv_loop_init returned error " << return_code.value(); + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_loop_init(&loop)); + if (return_code != 0) { + return absl::UnavailableError("uv_loop_init returned error " + return_code); } std::cout << "The loop is about to quit" << std::endl; // Run loop - return_code = api.sapi_uv_run(&loop, UV_RUN_DEFAULT); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_run failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "uv_run returned error " << return_code.value(); + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_run(&loop, UV_RUN_DEFAULT)); + if (return_code != 0) { + return absl::UnavailableError("uv_run returned error " + return_code); } // Close loop - return_code = api.sapi_uv_loop_close(&loop); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_loop_close failed: " << return_code.status(); + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_loop_close(&loop)); + if (return_code != 0) { + return absl::UnavailableError("uv_loop_close returned error " + + return_code); } - if (return_code.value() != 0) { - LOG(FATAL) << "uv_loop_close returned error " << return_code.value(); + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + if (absl::Status status = HelloWorld(); !status.ok()) { + LOG(ERROR) << "HelloWorld failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/libuv/examples/idle-basic.cc b/oss-internship-2020/libuv/examples/idle-basic.cc index 889676d..63e65d7 100644 --- a/oss-internship-2020/libuv/examples/idle-basic.cc +++ b/oss-internship-2020/libuv/examples/idle-basic.cc @@ -21,7 +21,7 @@ #include "sandboxed_api/util/flag.h" #include "uv_sapi.sapi.h" -class UVSapiIdleBasicSandbox : public UVSandbox { +class UVSapiIdleBasicSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -36,88 +36,74 @@ class UVSapiIdleBasicSandbox : public UVSandbox { } }; -int main(int argc, char* argv[]) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - google::InitGoogleLogging(argv[0]); - - absl::Status status; - +absl::Status IdleBasic() { // Initialize sandbox2 and sapi UVSapiIdleBasicSandbox sandbox; - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - UVApi api(&sandbox); + SAPI_RETURN_IF_ERROR(sandbox.Init()); + uv::UVApi api(&sandbox); // Get remote pointer to the IdleCallback method void* function_ptr; - status = sandbox.rpc_channel()->Symbol("IdleCallback", &function_ptr); - if (!status.ok()) { - LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Symbol failed: " << status; - } + SAPI_RETURN_IF_ERROR( + sandbox.rpc_channel()->Symbol("IdleCallback", &function_ptr)); sapi::v::RemotePtr idle_callback(function_ptr); // Allocate memory for the uv_idle_t object void* idle_voidptr; - status = sandbox.rpc_channel()->Allocate(sizeof(uv_idle_t), &idle_voidptr); - if (!status.ok()) { - LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Allocate failed: " << status; - } + SAPI_RETURN_IF_ERROR( + sandbox.rpc_channel()->Allocate(sizeof(uv_idle_t), &idle_voidptr)); sapi::v::RemotePtr idler(idle_voidptr); - absl::StatusOr return_code; + int return_code; // Get default loop - absl::StatusOr loop_voidptr = api.sapi_uv_default_loop(); - if (!loop_voidptr.ok()) { - LOG(FATAL) << "sapi_uv_default_loop failed: " << loop_voidptr.status(); - } - sapi::v::RemotePtr loop(loop_voidptr.value()); + SAPI_ASSIGN_OR_RETURN(void* loop_voidptr, api.sapi_uv_default_loop()); + sapi::v::RemotePtr loop(loop_voidptr); // Initialize idler - return_code = api.sapi_uv_idle_init(&loop, &idler); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_idle_init failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "sapi_uv_idle_init returned error " << return_code.value(); + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_idle_init(&loop, &idler)); + if (return_code != 0) { + return absl::UnavailableError("sapi_uv_idle_init returned error " + + return_code); } // Start idler - return_code = api.sapi_uv_idle_start(&idler, &idle_callback); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_idle_start failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "sapi_uv_idle_start returned error " << return_code.value(); + SAPI_ASSIGN_OR_RETURN(return_code, + api.sapi_uv_idle_start(&idler, &idle_callback)); + if (return_code != 0) { + return absl::UnavailableError("sapi_uv_idle_start returned error " + + return_code); } // Run loop - return_code = api.sapi_uv_run(&loop, UV_RUN_DEFAULT); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_run failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "uv_run returned error " << return_code.value(); + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_run(&loop, UV_RUN_DEFAULT)); + if (return_code != 0) { + return absl::UnavailableError("uv_run returned error " + return_code); } // Close idler sapi::v::NullPtr null_ptr; - status = api.sapi_uv_close(&idler, &null_ptr); - if (!status.ok()) { - LOG(FATAL) << "sapi_uv_close failed: " << status; - } + SAPI_RETURN_IF_ERROR(api.sapi_uv_close(&idler, &null_ptr)); // Close loop - return_code = api.sapi_uv_loop_close(&loop); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_loop_close failed: " << return_code.status(); - } + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_loop_close(&loop)); // UV_EBUSY is accepted because it is the return code of uv_loop_close // in the original example - if (return_code.value() != 0 && return_code.value() != UV_EBUSY) { - LOG(FATAL) << "uv_loop_close returned error " << return_code.value(); + if (return_code != 0 && return_code != UV_EBUSY) { + return absl::UnavailableError("uv_loop_close returned error " + + return_code); + } + + return absl::OkStatus(); +} + +int main(int argc, char* argv[]) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + google::InitGoogleLogging(argv[0]); + + if (absl::Status status = IdleBasic(); !status.ok()) { + LOG(ERROR) << "IdleBasic failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/libuv/examples/uvcat.cc b/oss-internship-2020/libuv/examples/uvcat.cc index 7cfa0b6..b693c81 100644 --- a/oss-internship-2020/libuv/examples/uvcat.cc +++ b/oss-internship-2020/libuv/examples/uvcat.cc @@ -21,7 +21,7 @@ #include "sandboxed_api/util/flag.h" #include "uv_sapi.sapi.h" -class UVSapiUVCatSandbox : public UVSandbox { +class UVSapiUVCatSandbox : public uv::UVSandbox { public: UVSapiUVCatSandbox(std::string filename) : filename(filename) {} @@ -46,74 +46,62 @@ class UVSapiUVCatSandbox : public UVSandbox { std::string filename; }; +absl::Status UVCat(std::string filearg) { + // Initialize sandbox2 and sapi + UVSapiUVCatSandbox sandbox(filearg); + SAPI_RETURN_IF_ERROR(sandbox.Init()); + uv::UVApi api(&sandbox); + + // Get remote pointer to the OnOpen method + void* function_ptr; + SAPI_RETURN_IF_ERROR(sandbox.rpc_channel()->Symbol("OnOpen", &function_ptr)); + sapi::v::RemotePtr on_open(function_ptr); + + // Get remote pointer to the open_req variable + void* open_req_voidptr; + SAPI_RETURN_IF_ERROR( + sandbox.rpc_channel()->Symbol("open_req", &open_req_voidptr)); + sapi::v::RemotePtr open_req(open_req_voidptr); + + // Get default loop + SAPI_ASSIGN_OR_RETURN(void* loop_voidptr, api.sapi_uv_default_loop()); + sapi::v::RemotePtr loop(loop_voidptr); + + int return_code; + + // Open file using the OnOpen callback (which will also read and print it) + sapi::v::ConstCStr filename(filearg.c_str()); + SAPI_ASSIGN_OR_RETURN( + return_code, api.sapi_uv_fs_open(&loop, &open_req, filename.PtrBefore(), + O_RDONLY, 0, &on_open)); + if (return_code != 0) { + return absl::UnavailableError("uv_fs_open returned error " + return_code); + } + + // Run loop + SAPI_ASSIGN_OR_RETURN(return_code, api.sapi_uv_run(&loop, UV_RUN_DEFAULT)); + if (return_code != 0) { + return absl::UnavailableError("uv_run returned error " + return_code); + } + + // Cleanup the request + SAPI_RETURN_IF_ERROR(api.sapi_uv_fs_req_cleanup(&open_req)); + + return absl::OkStatus(); +} + int main(int argc, char* argv[]) { gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); if (argc != 2) { - LOG(FATAL) << "wrong number of arguments (1 expected)"; - } - std::string filename_str = argv[1]; - - absl::Status status; - - // Initialize sandbox2 and sapi - UVSapiUVCatSandbox sandbox(filename_str); - status = sandbox.Init(); - if (!status.ok()) { - LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status; - } - UVApi api(&sandbox); - - // Get remote pointer to the OnOpen method - void* function_ptr; - status = sandbox.rpc_channel()->Symbol("OnOpen", &function_ptr); - if (!status.ok()) { - LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Symbol failed: " << status; - } - sapi::v::RemotePtr on_open(function_ptr); - - // Get remote pointer to the open_req variable - void* open_req_voidptr; - status = sandbox.rpc_channel()->Symbol("open_req", &open_req_voidptr); - if (!status.ok()) { - LOG(FATAL) << "sapi::Sandbox::rpc_channel()->Symbol failed: " << status; - } - sapi::v::RemotePtr open_req(open_req_voidptr); - - // Get default loop - absl::StatusOr loop_voidptr = api.sapi_uv_default_loop(); - if (!loop_voidptr.ok()) { - LOG(FATAL) << "sapi_uv_default_loop failed: " << loop_voidptr.status(); - } - sapi::v::RemotePtr loop(loop_voidptr.value()); - - absl::StatusOr return_code; - - // Open file using the OnOpen callback (which will also read and print it) - sapi::v::ConstCStr filename(filename_str.c_str()); - return_code = api.sapi_uv_fs_open(&loop, &open_req, filename.PtrBefore(), - O_RDONLY, 0, &on_open); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_fs_open failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "uv_fs_open returned error " << return_code.value(); + LOG(ERROR) << "wrong number of arguments (1 expected)"; + return EXIT_FAILURE; } - // Run loop - return_code = api.sapi_uv_run(&loop, UV_RUN_DEFAULT); - if (!return_code.ok()) { - LOG(FATAL) << "sapi_uv_run failed: " << return_code.status(); - } - if (return_code.value() != 0) { - LOG(FATAL) << "uv_run returned error " << return_code.value(); - } - - // Cleanup the request - status = api.sapi_uv_fs_req_cleanup(&open_req); - if (!status.ok()) { - LOG(FATAL) << "sapi_uv_fs_req_cleanup failed: " << status; + if (absl::Status status = UVCat(argv[1]); !status.ok()) { + LOG(ERROR) << "UVCat failed: " << status.ToString(); + return EXIT_FAILURE; } return EXIT_SUCCESS; diff --git a/oss-internship-2020/libuv/generator/wrapper_generator.py b/oss-internship-2020/libuv/generator/wrapper_generator.py index 5006589..43610a3 100644 --- a/oss-internship-2020/libuv/generator/wrapper_generator.py +++ b/oss-internship-2020/libuv/generator/wrapper_generator.py @@ -11,14 +11,20 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Script generating a wrapper API for LibUV.""" + +"""Script generating a wrapper API for LibUV. + .. note:: + This scriptis highly specific to LibUV's source code + and does not generalize to any other library + """ import sys +from typing import List import re import os -def get_var_type(string): +def get_var_type(string : str) -> str: """Gets the type from an argument variable (e.g. "int x" -> "int") """ @@ -32,7 +38,7 @@ def get_var_type(string): return " ".join(var.split(" ")[:-1]).strip() -def get_var_name(string): +def get_var_name(string : str) -> str: """Gets the name from an argument variable (e.g. "int x" -> "x") """ @@ -50,7 +56,7 @@ def get_var_name(string): return var.split(" ")[-1].strip() -def fix_method_type(string): +def fix_method_type(string : str) -> str: """Fixes the method type (e.g. "const int*" -> "const void*") """ @@ -69,7 +75,7 @@ def fix_method_type(string): return method_type -def fix_argument(string): +def fix_argument(string : str) -> str: """Fixes an argument (e.g. "const int* x" -> "const void* x") """ @@ -92,7 +98,7 @@ def fix_argument(string): return arg_type + " " + arg_name -def fix_call_argument(string): +def fix_call_argument(string : str) -> str: """Fixes an argument in a call the orignal method (e.g. "const int* x" -> "reinterpret_cast(x)") """ @@ -113,14 +119,14 @@ def fix_call_argument(string): return arg_name -def read_file(filename): +def read_file(filename : str) -> str: """Returns contents of filename as a string""" file = open(filename, "r") return str(file.read()) -def clean_file(text): +def clean_file(text : str) -> str: """Prepares the file for parsing In particular, removes comments and macros from text Additionally, moves pointer asterisks next to its type @@ -134,7 +140,7 @@ def clean_file(text): return result -def get_signatures(text): +def get_signatures(text : str) -> str: """Gets the signatures of all the methods in the header .. note:: This method only works on a certain version of LibUV's header """ @@ -148,71 +154,78 @@ def get_signatures(text): return zip(method_types, names, arguments_lists) -def write_method(method_type, name, arguments_list, header, source): - """Writes the method to both the header and the source files""" +def append_method(method_type : str, name : str, arguments_list : List[str], + header : List[str], source : List[str]) -> None: + """Writes the method to the header and the source list of lines""" - header.write(fix_method_type(method_type) + " sapi_" + name + "(" + - ", ".join(map(fix_argument, arguments_list)) + ");\n\n") - source.write(fix_method_type(method_type) + " sapi_" + name + "(" + - ", ".join(map(fix_argument, arguments_list)) + ") {\n") - source.write(" return " + name + "(" + - ", ".join(map(fix_call_argument, arguments_list)) + ");\n") - source.write("}\n\n") + header.append(fix_method_type(method_type) + " sapi_" + name + "(" + + ", ".join(map(fix_argument, arguments_list)) + ");") + source.append(fix_method_type(method_type) + " sapi_" + name + "(" + + ", ".join(map(fix_argument, arguments_list)) + ") {\n" + + " return " + name + "(" + + ", ".join(map(fix_call_argument, arguments_list)) + ");\n" + + "}") -def write_text(text, file): - """Writes text to file +def append_text(text : str, file : List[str]) -> None: + """Writes text to file list of lines Useful for additional methods, includes, extern "C"... """ - file.write(text) + file.append(text) -def generate_wrapper(): +def generate_wrapper() -> None: """Generates the wrapper""" + header_file = open(sys.argv[2], "w") + source_file = open(sys.argv[3], "w") + text = read_file(sys.argv[1]) text = clean_file(text) signatures = get_signatures(text) - header = open(sys.argv[2], "w") - source = open(sys.argv[3], "w") + header = [] + source = [] - write_text("#include \n\n", header) - write_text("extern \"C\" {\n\n", header) - write_text("#include \"" + os.path.abspath(header.name) + "\"\n\n", source) + append_text("#include ", header) + append_text("extern \"C\" {", header) + append_text("#include \"" + os.path.abspath(header_file.name) + "\"", source) for (method_type, name, arguments_list) in signatures: # These wrapper methods are manually added at the end if name in ("uv_once", "uv_loop_configure"): continue - write_method(method_type, name, arguments_list, header, source) + append_method(method_type, name, arguments_list, header, source) # Add sapi_uv_once (uv_once uses a differnet kind of callback) - write_text("void sapi_uv_once(void* guard, void (*callback)(void));\n\n", + append_text("void sapi_uv_once(void* guard, void (*callback)(void));", header) - write_text("void sapi_uv_once(void* guard, void (*callback)(void)) {\n" + + append_text("void sapi_uv_once(void* guard, void (*callback)(void)) {\n" + " return uv_once(reinterpret_cast(guard)," + - "callback);\n" + "}\n\n", source) + "callback);\n" + "}", source) # Add sapi_uv_loop_configure (uv_loop_configure is variadic) - write_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" + - ";\n\n", header) - write_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" + + append_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" + + ";", header) + append_text("int sapi_uv_loop_configure(void* loop, uv_loop_option option)" + " {\n return uv_loop_configure(" + - "reinterpret_cast(loop), option);\n" + "}\n\n", + "reinterpret_cast(loop), option);\n" + "}", source) # Add sapi_uv_loop_configure_int (uv_loop_configure is variadic) - write_text("int sapi_uv_loop_configure_int(void* loop, " + - "uv_loop_option option, int ap);\n\n", header) - write_text("int sapi_uv_loop_configure_int(void* loop, " + + append_text("int sapi_uv_loop_configure_int(void* loop, " + + "uv_loop_option option, int ap);", header) + append_text("int sapi_uv_loop_configure_int(void* loop, " + "uv_loop_option option, int ap) {\n" + " return uv_loop_configure(" + - "reinterpret_cast(loop), option, ap);\n}\n\n", + "reinterpret_cast(loop), option, ap);\n}", source) - write_text("} // extern \"C\"\n", header) + append_text("} // extern \"C\"\n", header) + + header_file.write("\n\n".join(header)) + source_file.write("\n\n".join(source)) generate_wrapper() diff --git a/oss-internship-2020/libuv/tests/test_array.cc b/oss-internship-2020/libuv/tests/test_array.cc index 572d1fc..82ceeed 100644 --- a/oss-internship-2020/libuv/tests/test_array.cc +++ b/oss-internship-2020/libuv/tests/test_array.cc @@ -21,7 +21,9 @@ #include "sandboxed_api/util/status_matchers.h" #include "uv_sapi.sapi.h" -class UVTestArraySapiSandbox : public UVSandbox { +namespace { + +class UVTestArraySapiSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -40,12 +42,12 @@ class UVTestArray : public ::testing::Test { protected: void SetUp() override { sandbox_ = std::make_unique(); - ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk()); - api_ = std::make_unique(sandbox_.get()); + ASSERT_THAT(sandbox_->Init(), sapi::IsOk()); + api_ = std::make_unique(sandbox_.get()); } std::unique_ptr sandbox_; - std::unique_ptr api_; + std::unique_ptr api_; }; TEST_F(UVTestArray, LoadAvg) { @@ -65,3 +67,5 @@ TEST_F(UVTestArray, LoadAvg) { ASSERT_GE(avg_buf[1], 0); ASSERT_GE(avg_buf[2], 0); } + +} // namespace diff --git a/oss-internship-2020/libuv/tests/test_callback.cc b/oss-internship-2020/libuv/tests/test_callback.cc index 275daa6..47ee138 100644 --- a/oss-internship-2020/libuv/tests/test_callback.cc +++ b/oss-internship-2020/libuv/tests/test_callback.cc @@ -21,7 +21,9 @@ #include "sandboxed_api/util/status_matchers.h" #include "uv_sapi.sapi.h" -class UVTestCallbackSapiSandbox : public UVSandbox { +namespace { + +class UVTestCallbackSapiSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -40,8 +42,8 @@ class UVTestCallback : public ::testing::Test { protected: void SetUp() override { sandbox_ = std::make_unique(); - ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk()); - api_ = std::make_unique(sandbox_.get()); + ASSERT_THAT(sandbox_->Init(), sapi::IsOk()); + api_ = std::make_unique(sandbox_.get()); } // Check sapi_uv_timer_init @@ -87,7 +89,7 @@ class UVTestCallback : public ::testing::Test { } std::unique_ptr sandbox_; - std::unique_ptr api_; + std::unique_ptr api_; static constexpr int kData = 1729; }; @@ -137,3 +139,5 @@ TEST_F(UVTestCallback, TimerCallback) { UVDefaultLoop(&loop); UVLoopClose(loop.PtrNone()); } + +} // namespace diff --git a/oss-internship-2020/libuv/tests/test_error.cc b/oss-internship-2020/libuv/tests/test_error.cc index 3f681fe..984c1a9 100644 --- a/oss-internship-2020/libuv/tests/test_error.cc +++ b/oss-internship-2020/libuv/tests/test_error.cc @@ -20,7 +20,9 @@ #include "sandboxed_api/util/status_matchers.h" #include "uv_sapi.sapi.h" -class UVTestErrorSapiSandbox : public UVSandbox { +namespace { + +class UVTestErrorSapiSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -37,8 +39,8 @@ class UVTestError : public ::testing::Test { protected: void SetUp() override { sandbox_ = std::make_unique(); - ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk()); - api_ = std::make_unique(sandbox_.get()); + ASSERT_THAT(sandbox_->Init(), sapi::IsOk()); + api_ = std::make_unique(sandbox_.get()); } // Check sapi_uv_strerror on error @@ -67,7 +69,7 @@ class UVTestError : public ::testing::Test { } std::unique_ptr sandbox_; - std::unique_ptr api_; + std::unique_ptr api_; }; TEST_F(UVTestError, ErrorMessage) { @@ -88,3 +90,5 @@ TEST_F(UVTestError, SystemError) { UVTranslateSysError(UV_EACCES); UVTranslateSysError(0); } + +} // namespace diff --git a/oss-internship-2020/libuv/tests/test_loop.cc b/oss-internship-2020/libuv/tests/test_loop.cc index 478cb62..9980f43 100644 --- a/oss-internship-2020/libuv/tests/test_loop.cc +++ b/oss-internship-2020/libuv/tests/test_loop.cc @@ -21,7 +21,9 @@ #include "sandboxed_api/util/status_matchers.h" #include "uv_sapi.sapi.h" -class UVTestLoopSapiSandbox : public UVSandbox { +namespace { + +class UVTestLoopSapiSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -39,8 +41,8 @@ class UVTestLoop : public ::testing::Test { protected: void SetUp() override { sandbox_ = std::make_unique(); - ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk()); - api_ = std::make_unique(sandbox_.get()); + ASSERT_THAT(sandbox_->Init(), sapi::IsOk()); + api_ = std::make_unique(sandbox_.get()); } // Check sapi_uv_loop_init @@ -69,7 +71,7 @@ class UVTestLoop : public ::testing::Test { } std::unique_ptr sandbox_; - std::unique_ptr api_; + std::unique_ptr api_; }; TEST_F(UVTestLoop, InitLoop) { @@ -100,3 +102,5 @@ TEST_F(UVTestLoop, DefaultLoop) { UVDefaultLoop(&loop); UVLoopClose(loop.PtrNone()); } + +} // namespace diff --git a/oss-internship-2020/libuv/tests/test_os.cc b/oss-internship-2020/libuv/tests/test_os.cc index 9d19171..a8195d9 100644 --- a/oss-internship-2020/libuv/tests/test_os.cc +++ b/oss-internship-2020/libuv/tests/test_os.cc @@ -21,7 +21,9 @@ #include "sandboxed_api/util/status_matchers.h" #include "uv_sapi.sapi.h" -class UVTestOSSapiSandbox : public UVSandbox { +namespace { + +class UVTestOSSapiSandbox : public uv::UVSandbox { private: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder*) override { @@ -43,12 +45,12 @@ class UVTestOS : public ::testing::Test { protected: void SetUp() override { sandbox_ = std::make_unique(); - ASSERT_THAT(sandbox_->Init(), ::sapi::IsOk()); - api_ = std::make_unique(sandbox_.get()); + ASSERT_THAT(sandbox_->Init(), sapi::IsOk()); + api_ = std::make_unique(sandbox_.get()); } std::unique_ptr sandbox_; - std::unique_ptr api_; + std::unique_ptr api_; static constexpr size_t kBigBufLen = 4096; static constexpr size_t kSmallBufLen = 1; @@ -131,3 +133,5 @@ TEST_F(UVTestOS, TmpDirSmall) { // Test error code is as expected ASSERT_EQ(error_code, expected_error_code); } + +} // namespace