mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
127176d72f
PiperOrigin-RevId: 559733768 Change-Id: Ia38f4c176e9f0abbfdb3a8f1109f482d8870eb0f
172 lines
5.2 KiB
C++
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_
|