1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <lib/fidl/coding.h>
6 
7 #include <stdalign.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 
11 #include <lib/fidl/internal.h>
12 #include <zircon/assert.h>
13 #include <zircon/compiler.h>
14 
15 #ifdef __Fuchsia__
16 #include <zircon/syscalls.h>
17 #endif
18 
19 #include "buffer_walker.h"
20 
21 // TODO(kulakowski) Design zx_status_t error values.
22 
23 namespace {
24 
25 class FidlDecoder final : public fidl::internal::BufferWalker<FidlDecoder, true, false> {
26     typedef fidl::internal::BufferWalker<FidlDecoder, true, false> Super;
27 
28 public:
FidlDecoder(const fidl_type_t * type,void * bytes,uint32_t num_bytes,const zx_handle_t * handles,uint32_t num_handles,const char ** out_error_msg)29     FidlDecoder(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
30                 const zx_handle_t* handles, uint32_t num_handles, const char** out_error_msg)
31         : Super(type), bytes_(static_cast<uint8_t*>(bytes)), num_bytes_(num_bytes),
32           handles_(handles), num_handles_(num_handles), out_error_msg_(out_error_msg) {}
33 
Walk()34     void Walk() {
35         if (handles_ == nullptr && num_handles_ != 0u) {
36             SetError("Cannot provide non-zero handle count and null handle pointer");
37             return;
38         }
39         Super::Walk();
40         if (status_ == ZX_OK && handle_idx() != num_handles()) {
41             SetError("message did not contain the specified number of handles");
42         }
43     }
44 
bytes() const45     uint8_t* bytes() const { return bytes_; }
num_bytes() const46     uint32_t num_bytes() const { return num_bytes_; }
num_handles() const47     uint32_t num_handles() const { return num_handles_; }
48 
ValidateOutOfLineStorageClaim(const void * a,const void * b)49     bool ValidateOutOfLineStorageClaim(const void* a, const void* b) {
50         return true;
51     }
52 
UnclaimedHandle(zx_handle_t * out_handle)53     void UnclaimedHandle(zx_handle_t* out_handle) {}
ClaimedHandle(zx_handle_t * out_handle,uint32_t idx)54     void ClaimedHandle(zx_handle_t* out_handle, uint32_t idx) {
55         if (out_handle != nullptr) {
56             *out_handle = handles_[idx];
57 #ifdef __Fuchsia__
58         } else {
59             // Return value intentionally ignored: this is best-effort cleanup.
60             zx_handle_close(handles_[idx]);
61 #endif
62         }
63     }
64 
GetPointerState(const void * ptr) const65     PointerState GetPointerState(const void* ptr) const {
66         return static_cast<PointerState>(*static_cast<const uintptr_t*>(ptr));
67     }
GetHandleState(zx_handle_t p) const68     HandleState GetHandleState(zx_handle_t p) const {
69         return static_cast<HandleState>(p);
70     }
71 
72     template <class T>
UpdatePointer(T * p,T v)73     void UpdatePointer(T* p, T v) {
74         *p = v;
75     }
76 
SetError(const char * error_msg)77     void SetError(const char* error_msg) {
78         status_ = ZX_ERR_INVALID_ARGS;
79         if (out_error_msg_ != nullptr) {
80             *out_error_msg_ = error_msg;
81         }
82 #ifdef __Fuchsia__
83         if (handles_) {
84             // Return value intentionally ignored: this is best-effort cleanup.
85             zx_handle_close_many(handles_, num_handles());
86         }
87 #endif
88     }
89 
status() const90     zx_status_t status() const { return status_; }
91 
92 private:
93     uint8_t* const bytes_;
94     const uint32_t num_bytes_;
95     const zx_handle_t* const handles_;
96     const uint32_t num_handles_;
97     const char** const out_error_msg_;
98     zx_status_t status_ = ZX_OK;
99 };
100 
101 } // namespace
102 
fidl_decode(const fidl_type_t * type,void * bytes,uint32_t num_bytes,const zx_handle_t * handles,uint32_t num_handles,const char ** out_error_msg)103 zx_status_t fidl_decode(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
104                         const zx_handle_t* handles, uint32_t num_handles,
105                         const char** out_error_msg) {
106     FidlDecoder decoder(type, bytes, num_bytes, handles, num_handles, out_error_msg);
107     decoder.Walk();
108     return decoder.status();
109 }
110 
fidl_decode_msg(const fidl_type_t * type,fidl_msg_t * msg,const char ** out_error_msg)111 zx_status_t fidl_decode_msg(const fidl_type_t* type, fidl_msg_t* msg,
112                             const char** out_error_msg) {
113     return fidl_decode(type, msg->bytes, msg->num_bytes, msg->handles,
114                        msg->num_handles, out_error_msg);
115 }
116