xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/var_array.h (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
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