blob: 0feb6c1f248d3509b65d513dc9c0e3b2e99d1b86 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/fidl/coding.h>
#include <lib/fidl/internal.h>
#include <lib/fidl/visitor.h>
#include <lib/fidl/walker.h>
#include <stdalign.h>
#include <zircon/assert.h>
#include <zircon/compiler.h>
#include <zircon/syscalls.h>
#include <cstdint>
#include <cstdlib>
#include <limits>
namespace {
struct Position {
void* addr;
Position operator+(uint32_t size) const {
return Position{reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(addr) + size)};
}
Position& operator+=(uint32_t size) {
*this = *this + size;
return *this;
}
template <typename T>
constexpr T* Get() const {
return reinterpret_cast<T*>(addr);
}
};
struct EnvelopeCheckpoint {};
class FidlHandleCloser final
: public fidl::Visitor<fidl::MutatingVisitorTrait, Position, EnvelopeCheckpoint> {
public:
FidlHandleCloser(const char** out_error_msg) : out_error_msg_(out_error_msg) {}
using Position = Position;
static constexpr bool kOnlyWalkResources = true;
static constexpr bool kContinueAfterConstraintViolation = true;
Status VisitAbsentPointerInNonNullableCollection(ObjectPointerPointer object_ptr_ptr) {
SetError("absent pointer disallowed in non-nullable collection");
return Status::kConstraintViolationError;
}
Status VisitPointer(Position ptr_position, PointeeType pointee_type,
ObjectPointerPointer object_ptr_ptr, uint32_t inline_size,
Position* out_position) {
// Just follow the pointer into the child object
*out_position = Position{*object_ptr_ptr};
return Status::kSuccess;
}
Status VisitHandle(Position handle_position, HandlePointer handle, zx_rights_t handle_rights,
zx_obj_type_t handle_subtype) {
// Close the handle and mark it as invalid
zx_handle_close(*handle);
*handle = ZX_HANDLE_INVALID;
return Status::kSuccess;
}
Status VisitVectorOrStringCount(CountPointer ptr) { return Status::kSuccess; }
template <typename MaskType>
Status VisitInternalPadding(Position padding_position, MaskType mask) {
return Status::kSuccess;
}
EnvelopeCheckpoint EnterEnvelope() { return {}; }
Status LeaveEnvelope(EnvelopePointer envelope, EnvelopeCheckpoint prev_checkpoint) {
return Status::kSuccess;
}
Status VisitUnknownEnvelope(EnvelopePointer envelope, FidlIsResource is_resource) {
return Status::kSuccess;
}
void OnError(const char* error) { SetError(error); }
zx_status_t status() const { return status_; }
private:
void SetError(const char* error_msg) {
if (status_ == ZX_OK) {
status_ = ZX_ERR_INVALID_ARGS;
if (out_error_msg_ != nullptr) {
*out_error_msg_ = error_msg;
}
}
}
// Message state passed in to the constructor.
const char** const out_error_msg_;
zx_status_t status_ = ZX_OK;
};
} // namespace
zx_status_t fidl_close_handles(const fidl_type_t* type, void* value, const char** out_error_msg) {
auto set_error = [&out_error_msg](const char* msg) {
if (out_error_msg)
*out_error_msg = msg;
};
if (value == nullptr) {
set_error("Cannot close handles for null message");
return ZX_ERR_INVALID_ARGS;
}
if (type == nullptr) {
set_error("Cannot close handles for a null fidl type");
return ZX_ERR_INVALID_ARGS;
}
FidlHandleCloser handle_closer(out_error_msg);
fidl::Walk(handle_closer, type, Position{reinterpret_cast<uint8_t*>(value)});
return handle_closer.status();
}