• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
22 #include <type_traits>
23 
24 #include "absl/log/check.h"
25 #include "absl/log/log.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/string_view.h"
29 #include "sandboxed_api/rpcchannel.h"
30 #include "sandboxed_api/util/status_macros.h"
31 #include "sandboxed_api/var_abstract.h"
32 #include "sandboxed_api/var_type.h"
33 
34 namespace sapi::v {
35 
36 // Class representing an array.
37 template <class T>
38 class Array : public Var {
39  public:
40   // The array is not owned by this object.
Array(T * arr,size_t nelem)41   Array(T* arr, size_t nelem)
42       : arr_(arr),
43         nelem_(nelem),
44         total_size_(nelem_ * sizeof(T)),
45         buffer_owned_(false) {
46     SetLocal(const_cast<std::remove_const_t<T>*>(arr_));
47   }
48 
49   // The array is allocated and owned by this object.
Array(size_t nelem)50   explicit Array(size_t nelem)
51       : nelem_(nelem), total_size_(nelem_ * sizeof(T)), buffer_owned_(true) {
52     void* storage = malloc(sizeof(T) * nelem);
53     CHECK(storage != nullptr);
54     SetLocal(storage);
55     arr_ = static_cast<T*>(storage);
56   }
57 
Array(Array && other)58   Array(Array&& other) { *this = std::move(other); }
59   Array& operator=(Array&& other) {
60     if (this != &other) {
61       Var::operator=(std::move(other));
62       using std::swap;
63       swap(arr_, other.arr_);
64       swap(nelem_, other.nelem_);
65       swap(total_size_, other.total_size_);
66       swap(buffer_owned_, other.buffer_owned_);
67       other.buffer_owned_ = false;  // If it was owned before, we own it now.
68     }
69     return *this;
70   }
71 
~Array()72   virtual ~Array() {
73     if (buffer_owned_) {
74       free(const_cast<std::remove_const_t<T>*>(arr_));
75     }
76   }
77 
78   T& operator[](size_t v) const { return arr_[v]; }
GetData()79   T* GetData() const { return arr_; }
80 
GetNElem()81   size_t GetNElem() const { return nelem_; }
GetSize()82   size_t GetSize() const final { return total_size_; }
GetType()83   Type GetType() const final { return Type::kArray; }
GetTypeString()84   std::string GetTypeString() const final { return "Array"; }
ToString()85   std::string ToString() const override {
86     return absl::StrCat("Array, elem size: ", sizeof(T),
87                         " B., total size: ", total_size_,
88                         " B., nelems: ", GetNElem());
89   }
90 
91   // Resizes the local and remote buffer using realloc(). Note that this will
92   // make all pointers to the current data (inside and outside of the sandbox)
93   // invalid.
Resize(RPCChannel * rpc_channel,size_t nelems)94   absl::Status Resize(RPCChannel* rpc_channel, size_t nelems) {
95     size_t absolute_size = sizeof(T) * nelems;
96     // Resize local buffer.
97     SAPI_RETURN_IF_ERROR(EnsureOwnedLocalBuffer(absolute_size));
98 
99     // Resize remote buffer and update local pointer.
100     void* new_addr;
101 
102     SAPI_RETURN_IF_ERROR(
103         rpc_channel->Reallocate(GetRemote(), absolute_size, &new_addr));
104     if (!new_addr) {
105       return absl::UnavailableError("Reallocate() returned nullptr");
106     }
107     SetRemote(new_addr);
108     return absl::OkStatus();
109   }
110 
111  private:
112   friend class LenVal;
113 
114   // Resizes the internal storage.
EnsureOwnedLocalBuffer(size_t size)115   absl::Status EnsureOwnedLocalBuffer(size_t size) {
116     if (size % sizeof(T)) {
117       return absl::FailedPreconditionError(
118           "Array size not a multiple of the item size");
119     }
120     // Do not (re-)allocate memory if the new size matches our size - except
121     // when we don't own that buffer.
122     if (size == total_size_ && buffer_owned_) {
123       return absl::OkStatus();
124     }
125     void* new_addr = nullptr;
126     if (buffer_owned_) {
127       new_addr = realloc(arr_, size);
128     } else {
129       new_addr = malloc(size);
130       if (new_addr) {
131         memcpy(new_addr, arr_, std::min(size, total_size_));
132         buffer_owned_ = true;
133       }
134     }
135     if (!new_addr) {
136       return absl::UnavailableError("(Re-)malloc failed");
137     }
138 
139     arr_ = static_cast<T*>(new_addr);
140     total_size_ = size;
141     nelem_ = size / sizeof(T);
142     SetLocal(new_addr);
143     return absl::OkStatus();
144   }
145 
146   // Pointer to the data, owned by the object if buffer_owned_ is 'true'.
147   T* arr_ = nullptr;
148   size_t nelem_ = 0;           // Number of elements
149   size_t total_size_ = 0;      // Total size in bytes
150   bool buffer_owned_ = false;  // Whether we own the buffer
151 };
152 
153 // Specialized Array class for representing NUL-terminated C-style strings. The
154 // buffer is owned by the class, and is mutable.
155 class CStr : public Array<char> {
156  public:
CStr(absl::string_view cstr)157   explicit CStr(absl::string_view cstr) : Array<char>(cstr.size() + 1) {
158     std::copy(cstr.begin(), cstr.end(), GetData());
159     GetData()[cstr.size()] = '\0';
160   }
161 
ToString()162   std::string ToString() const final {
163     return absl::StrCat("CStr: len(w/o NUL):", strlen(GetData()), ", ['",
164                         GetData(), "']");
165   }
166 };
167 
168 // Specialized Array class for representing NUL-terminated C-style strings. The
169 // buffer is not owned by the class and is not mutable.
170 class ConstCStr : public Array<const char> {
171  public:
ConstCStr(const char * cstr)172   explicit ConstCStr(const char* cstr)
173       : Array<const char>(cstr, strlen(cstr) + 1) {}
174 
ToString()175   std::string ToString() const final {
176     return absl::StrCat("ConstCStr: len(w/o NUL):", strlen(GetData()), ", ['",
177                         GetData(), "']");
178   }
179 };
180 
181 }  // namespace sapi::v
182 
183 #endif  // SANDBOXED_API_VAR_ARRAY_H_
184