sandboxed-api/sandboxed_api/var_array.h

172 lines
5.2 KiB
C++

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.
#ifndef SANDBOXED_API_VAR_ARRAY_H_
#define SANDBOXED_API_VAR_ARRAY_H_
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <type_traits>
#include "absl/base/macros.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "sandboxed_api/rpcchannel.h"
#include "sandboxed_api/util/status_macros.h"
#include "sandboxed_api/var_abstract.h"
#include "sandboxed_api/var_ptr.h"
namespace sapi::v {
// Class representing an array.
template <class T>
class Array : public Var {
public:
// The array is not owned by this object.
Array(T* arr, size_t nelem)
: arr_(arr),
nelem_(nelem),
total_size_(nelem_ * sizeof(T)),
buffer_owned_(false) {
SetLocal(const_cast<std::remove_const_t<T>*>(arr_));
}
// The array is allocated and owned by this object.
explicit Array(size_t nelem)
: nelem_(nelem), total_size_(nelem_ * sizeof(T)), buffer_owned_(true) {
void* storage = malloc(sizeof(T) * nelem);
CHECK(storage != nullptr);
SetLocal(storage);
arr_ = static_cast<T*>(storage);
}
virtual ~Array() {
if (buffer_owned_) {
free(const_cast<std::remove_const_t<T>*>(arr_));
}
}
T& operator[](size_t v) const { return arr_[v]; }
T* GetData() const { return arr_; }
size_t GetNElem() const { return nelem_; }
size_t GetSize() const final { return total_size_; }
Type GetType() const final { return Type::kArray; }
std::string GetTypeString() const final { return "Array"; }
std::string ToString() const override {
return absl::StrCat("Array, elem size: ", sizeof(T),
" B., total size: ", total_size_,
" B., nelems: ", GetNElem());
}
// Resizes the local and remote buffer using realloc(). Note that this will
// make all pointers to the current data (inside and outside of the sandbox)
// invalid.
absl::Status Resize(RPCChannel* rpc_channel, size_t nelems) {
size_t absolute_size = sizeof(T) * nelems;
// Resize local buffer.
SAPI_RETURN_IF_ERROR(EnsureOwnedLocalBuffer(absolute_size));
// Resize remote buffer and update local pointer.
void* new_addr;
SAPI_RETURN_IF_ERROR(
rpc_channel->Reallocate(GetRemote(), absolute_size, &new_addr));
if (!new_addr) {
return absl::UnavailableError("Reallocate() returned nullptr");
}
SetRemote(new_addr);
return absl::OkStatus();
}
private:
friend class LenVal;
// Resizes the internal storage.
absl::Status EnsureOwnedLocalBuffer(size_t size) {
if (size % sizeof(T)) {
return absl::FailedPreconditionError(
"Array size not a multiple of the item size");
}
// Do not (re-)allocate memory if the new size matches our size - except
// when we don't own that buffer.
if (size == total_size_ && buffer_owned_) {
return absl::OkStatus();
}
void* new_addr = nullptr;
if (buffer_owned_) {
new_addr = realloc(arr_, size);
} else {
new_addr = malloc(size);
if (new_addr) {
memcpy(new_addr, arr_, std::min(size, total_size_));
buffer_owned_ = true;
}
}
if (!new_addr) {
return absl::UnavailableError("(Re-)malloc failed");
}
arr_ = static_cast<T*>(new_addr);
total_size_ = size;
nelem_ = size / sizeof(T);
SetLocal(new_addr);
return absl::OkStatus();
}
// Pointer to the data, owned by the object if buffer_owned_ is 'true'.
T* arr_;
size_t nelem_; // Number of elements
size_t total_size_; // Total size in bytes
bool buffer_owned_; // Whether we own the buffer
};
// Specialized Array class for representing NUL-terminated C-style strings. The
// buffer is owned by the class, and is mutable.
class CStr : public Array<char> {
public:
explicit CStr(absl::string_view cstr) : Array<char>(cstr.size() + 1) {
std::copy(cstr.begin(), cstr.end(), GetData());
GetData()[cstr.size()] = '\0';
}
std::string ToString() const final {
return absl::StrCat("CStr: len(w/o NUL):", strlen(GetData()), ", ['",
GetData(), "']");
}
};
// Specialized Array class for representing NUL-terminated C-style strings. The
// buffer is not owned by the class and is not mutable.
class ConstCStr : public Array<const char> {
public:
explicit ConstCStr(const char* cstr)
: Array<const char>(cstr, strlen(cstr) + 1) {}
std::string ToString() const final {
return absl::StrCat("ConstCStr: len(w/o NUL):", strlen(GetData()), ", ['",
GetData(), "']");
}
};
} // namespace sapi::v
#endif // SANDBOXED_API_VAR_ARRAY_H_