blob: 5d72fc1368d73911b74b8a5b4eb65457a11d058f [file] [log] [blame] [edit]
// 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_WIRE_FORMAT_VERSION_V1, 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;
static constexpr bool kValidateEnvelopeInlineBit = 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,
FidlMemcpyCompatibility pointee_memcpy_compatibility,
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(EnvelopeType in_envelope, EnvelopePointer out_envelope,
EnvelopeCheckpoint prev_checkpoint) {
return Status::kSuccess;
}
Status LeaveInlinedEnvelope(EnvelopeType in_envelope, EnvelopePointer out_envelope,
EnvelopeCheckpoint prev_checkpoint) {
return Status::kSuccess;
}
Status VisitUnknownEnvelope(EnvelopeType envelope_copy, EnvelopePointer envelope_ptr,
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<FIDL_WIRE_FORMAT_VERSION_V1>(handle_closer, type,
Position{reinterpret_cast<uint8_t*>(value)});
return handle_closer.status();
}