1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SANDBOXED_API_VAR_ARRAY_H_ 16 #define SANDBOXED_API_VAR_ARRAY_H_ 17 18 #include <algorithm> 19 #include <cstdlib> 20 #include <cstring> 21 #include <memory> 22 #include <string> 23 #include <type_traits> 24 25 #include "absl/base/macros.h" 26 #include "absl/log/check.h" 27 #include "absl/log/log.h" 28 #include "absl/status/status.h" 29 #include "absl/strings/str_cat.h" 30 #include "absl/strings/string_view.h" 31 #include "sandboxed_api/rpcchannel.h" 32 #include "sandboxed_api/util/status_macros.h" 33 #include "sandboxed_api/var_abstract.h" 34 #include "sandboxed_api/var_ptr.h" 35 36 namespace sapi::v { 37 38 // Class representing an array. 39 template <class T> 40 class Array : public Var { 41 public: 42 // The array is not owned by this object. Array(T * arr,size_t nelem)43 Array(T* arr, size_t nelem) 44 : arr_(arr), 45 nelem_(nelem), 46 total_size_(nelem_ * sizeof(T)), 47 buffer_owned_(false) { 48 SetLocal(const_cast<std::remove_const_t<T>*>(arr_)); 49 } 50 51 // The array is allocated and owned by this object. Array(size_t nelem)52 explicit Array(size_t nelem) 53 : nelem_(nelem), total_size_(nelem_ * sizeof(T)), buffer_owned_(true) { 54 void* storage = malloc(sizeof(T) * nelem); 55 CHECK(storage != nullptr); 56 SetLocal(storage); 57 arr_ = static_cast<T*>(storage); 58 } 59 ~Array()60 virtual ~Array() { 61 if (buffer_owned_) { 62 free(const_cast<std::remove_const_t<T>*>(arr_)); 63 } 64 } 65 66 T& operator[](size_t v) const { return arr_[v]; } GetData()67 T* GetData() const { return arr_; } 68 GetNElem()69 size_t GetNElem() const { return nelem_; } GetSize()70 size_t GetSize() const final { return total_size_; } GetType()71 Type GetType() const final { return Type::kArray; } GetTypeString()72 std::string GetTypeString() const final { return "Array"; } ToString()73 std::string ToString() const override { 74 return absl::StrCat("Array, elem size: ", sizeof(T), 75 " B., total size: ", total_size_, 76 " B., nelems: ", GetNElem()); 77 } 78 79 // Resizes the local and remote buffer using realloc(). Note that this will 80 // make all pointers to the current data (inside and outside of the sandbox) 81 // invalid. Resize(RPCChannel * rpc_channel,size_t nelems)82 absl::Status Resize(RPCChannel* rpc_channel, size_t nelems) { 83 size_t absolute_size = sizeof(T) * nelems; 84 // Resize local buffer. 85 SAPI_RETURN_IF_ERROR(EnsureOwnedLocalBuffer(absolute_size)); 86 87 // Resize remote buffer and update local pointer. 88 void* new_addr; 89 90 SAPI_RETURN_IF_ERROR( 91 rpc_channel->Reallocate(GetRemote(), absolute_size, &new_addr)); 92 if (!new_addr) { 93 return absl::UnavailableError("Reallocate() returned nullptr"); 94 } 95 SetRemote(new_addr); 96 return absl::OkStatus(); 97 } 98 99 private: 100 friend class LenVal; 101 102 // Resizes the internal storage. EnsureOwnedLocalBuffer(size_t size)103 absl::Status EnsureOwnedLocalBuffer(size_t size) { 104 if (size % sizeof(T)) { 105 return absl::FailedPreconditionError( 106 "Array size not a multiple of the item size"); 107 } 108 // Do not (re-)allocate memory if the new size matches our size - except 109 // when we don't own that buffer. 110 if (size == total_size_ && buffer_owned_) { 111 return absl::OkStatus(); 112 } 113 void* new_addr = nullptr; 114 if (buffer_owned_) { 115 new_addr = realloc(arr_, size); 116 } else { 117 new_addr = malloc(size); 118 if (new_addr) { 119 memcpy(new_addr, arr_, std::min(size, total_size_)); 120 buffer_owned_ = true; 121 } 122 } 123 if (!new_addr) { 124 return absl::UnavailableError("(Re-)malloc failed"); 125 } 126 127 arr_ = static_cast<T*>(new_addr); 128 total_size_ = size; 129 nelem_ = size / sizeof(T); 130 SetLocal(new_addr); 131 return absl::OkStatus(); 132 } 133 134 // Pointer to the data, owned by the object if buffer_owned_ is 'true'. 135 T* arr_; 136 size_t nelem_; // Number of elements 137 size_t total_size_; // Total size in bytes 138 bool buffer_owned_; // Whether we own the buffer 139 }; 140 141 // Specialized Array class for representing NUL-terminated C-style strings. The 142 // buffer is owned by the class, and is mutable. 143 class CStr : public Array<char> { 144 public: CStr(absl::string_view cstr)145 explicit CStr(absl::string_view cstr) : Array<char>(cstr.size() + 1) { 146 std::copy(cstr.begin(), cstr.end(), GetData()); 147 GetData()[cstr.size()] = '\0'; 148 } 149 ToString()150 std::string ToString() const final { 151 return absl::StrCat("CStr: len(w/o NUL):", strlen(GetData()), ", ['", 152 GetData(), "']"); 153 } 154 }; 155 156 // Specialized Array class for representing NUL-terminated C-style strings. The 157 // buffer is not owned by the class and is not mutable. 158 class ConstCStr : public Array<const char> { 159 public: ConstCStr(const char * cstr)160 explicit ConstCStr(const char* cstr) 161 : Array<const char>(cstr, strlen(cstr) + 1) {} 162 ToString()163 std::string ToString() const final { 164 return absl::StrCat("ConstCStr: len(w/o NUL):", strlen(GetData()), ", ['", 165 GetData(), "']"); 166 } 167 }; 168 169 } // namespace sapi::v 170 171 #endif // SANDBOXED_API_VAR_ARRAY_H_ 172