xref: /third_party/node/deps/uvwasi/src/wasi_serdes.c (revision 1cb0ef41)
1#include "wasi_serdes.h"
2#include "wasi_types.h"
3
4void uvwasi_serdes_write_uint64_t(void* ptr,
5                                  size_t offset,
6                                  uint64_t value) {
7  uvwasi_serdes_write_uint32_t(ptr, offset, (uint32_t) value);
8  uvwasi_serdes_write_uint32_t(ptr, offset + 4, value >> 32);
9}
10
11void uvwasi_serdes_write_uint32_t(void* ptr,
12                                  size_t offset,
13                                  uint32_t value) {
14  uvwasi_serdes_write_uint16_t(ptr, offset, (uint16_t) value);
15  uvwasi_serdes_write_uint16_t(ptr, offset + 2, value >> 16);
16}
17
18void uvwasi_serdes_write_uint16_t(void* ptr,
19                                  size_t offset,
20                                  uint16_t value) {
21  uvwasi_serdes_write_uint8_t(ptr, offset, (uint8_t) value);
22  uvwasi_serdes_write_uint8_t(ptr, offset + 1, value >> 8);
23}
24
25void uvwasi_serdes_write_uint8_t(void* ptr,
26                                 size_t offset,
27                                 uint8_t value) {
28  ((uint8_t*) ptr)[offset] = value;
29}
30
31uint64_t uvwasi_serdes_read_uint64_t(const void* ptr, size_t offset) {
32  uint64_t low = uvwasi_serdes_read_uint32_t(ptr, offset);
33  uint64_t high = uvwasi_serdes_read_uint32_t(ptr, offset + 4);
34  return low | (high << 32);
35}
36
37uint32_t uvwasi_serdes_read_uint32_t(const void* ptr, size_t offset) {
38  uint32_t low = uvwasi_serdes_read_uint16_t(ptr, offset);
39  uint32_t high = uvwasi_serdes_read_uint16_t(ptr, offset + 2);
40  return low | (high << 16);
41}
42
43uint16_t uvwasi_serdes_read_uint16_t(const void* ptr, size_t offset) {
44  uint16_t low = uvwasi_serdes_read_uint8_t(ptr, offset);
45  uint16_t high = uvwasi_serdes_read_uint8_t(ptr, offset + 1);
46  return low | (high << 8);
47}
48
49uint8_t uvwasi_serdes_read_uint8_t(const void* ptr,  size_t offset) {
50  return ((const uint8_t*) ptr)[offset];
51}
52
53#define TYPE_SWITCH switch (value->type)
54
55#define ALL_TYPES(STRUCT, FIELD, ALIAS)                                       \
56                                                                              \
57  ALIAS(advice_t,        uint8_t)                                             \
58  ALIAS(clockid_t,       uint32_t)                                            \
59  ALIAS(device_t,        uint64_t)                                            \
60  ALIAS(dircookie_t,     uint64_t)                                            \
61  ALIAS(errno_t,         uint16_t)                                            \
62  ALIAS(eventrwflags_t,  uint16_t)                                            \
63  ALIAS(eventtype_t,     uint8_t)                                             \
64  ALIAS(exitcode_t,      uint32_t)                                            \
65  ALIAS(fd_t,            uint32_t)                                            \
66  ALIAS(fdflags_t,       uint16_t)                                            \
67  ALIAS(filesize_t,      uint64_t)                                            \
68  ALIAS(filetype_t,      uint8_t)                                             \
69  ALIAS(fstflags_t,      uint16_t)                                            \
70  ALIAS(inode_t,         uint64_t)                                            \
71  ALIAS(linkcount_t,     uint64_t)                                            \
72  ALIAS(lookupflags_t,   uint32_t)                                            \
73  ALIAS(oflags_t,        uint16_t)                                            \
74  ALIAS(preopentype_t,   uint8_t)                                             \
75  ALIAS(riflags_t,       uint16_t)                                            \
76  ALIAS(rights_t,        uint64_t)                                            \
77  ALIAS(roflags_t,       uint16_t)                                            \
78  ALIAS(sdflags_t,       uint8_t)                                             \
79  ALIAS(siflags_t,       uint16_t)                                            \
80  ALIAS(signal_t,        uint8_t)                                             \
81  ALIAS(size_t,          uint32_t)                                            \
82  ALIAS(subclockflags_t, uint16_t)                                            \
83  ALIAS(timestamp_t,     uint64_t)                                            \
84  ALIAS(userdata_t,      uint64_t)                                            \
85  ALIAS(whence_t,        uint8_t)                                             \
86                                                                              \
87  STRUCT(dirent_t) {                                                          \
88    FIELD( 0, dircookie_t, d_next);                                           \
89    FIELD( 8, inode_t,     d_ino);                                            \
90    FIELD(16, uint32_t,    d_namlen);                                         \
91    FIELD(20, filetype_t,  d_type);                                           \
92  }                                                                           \
93                                                                              \
94  STRUCT(fdstat_t) {                                                          \
95    FIELD( 0, filetype_t, fs_filetype);                                       \
96    FIELD( 2, fdflags_t,  fs_flags);                                          \
97    FIELD( 8, rights_t,   fs_rights_base);                                    \
98    FIELD(16, rights_t,   fs_rights_inheriting);                              \
99  }                                                                           \
100                                                                              \
101  STRUCT(filestat_t) {                                                        \
102    FIELD( 0, device_t,    st_dev);                                           \
103    FIELD( 8, inode_t,     st_ino);                                           \
104    FIELD(16, filetype_t,  st_filetype);                                      \
105    FIELD(24, linkcount_t, st_nlink);                                         \
106    FIELD(32, filesize_t,  st_size);                                          \
107    FIELD(40, timestamp_t, st_atim);                                          \
108    FIELD(48, timestamp_t, st_mtim);                                          \
109    FIELD(56, timestamp_t, st_ctim);                                          \
110  }                                                                           \
111                                                                              \
112  STRUCT(prestat_t) {                                                         \
113    FIELD(0, preopentype_t, pr_type);                                         \
114    FIELD(4, uint32_t,      u.dir.pr_name_len);                               \
115  }                                                                           \
116                                                                              \
117  STRUCT(event_t) {                                                           \
118    FIELD( 0, userdata_t,  userdata);                                         \
119    FIELD( 8, errno_t,     error);                                            \
120    FIELD(10, eventtype_t, type);                                             \
121    TYPE_SWITCH {                                                             \
122      case UVWASI_EVENTTYPE_FD_READ:                                          \
123      case UVWASI_EVENTTYPE_FD_WRITE:                                         \
124        FIELD(16, filesize_t,     u.fd_readwrite.nbytes);                     \
125        FIELD(24, eventrwflags_t, u.fd_readwrite.flags);                      \
126    }                                                                         \
127  }                                                                           \
128                                                                              \
129  STRUCT(subscription_t) {                                                    \
130    FIELD(0, userdata_t,  userdata);                                          \
131    FIELD(8, eventtype_t, type);                                              \
132    TYPE_SWITCH {                                                             \
133      case UVWASI_EVENTTYPE_CLOCK:                                            \
134        FIELD(16, clockid_t,       u.clock.clock_id);                         \
135        FIELD(24, timestamp_t,     u.clock.timeout);                          \
136        FIELD(32, timestamp_t,     u.clock.precision);                        \
137        FIELD(40, subclockflags_t, u.clock.flags);                            \
138        break;                                                                \
139      case UVWASI_EVENTTYPE_FD_READ:                                          \
140      case UVWASI_EVENTTYPE_FD_WRITE:                                         \
141        FIELD(16, fd_t, u.fd_readwrite.fd);                                   \
142    }                                                                         \
143  }                                                                           \
144
145#define WRITE_STRUCT(name)                                                    \
146  void uvwasi_serdes_write_##name(void* ptr,                                  \
147                                  size_t offset,                              \
148                                  const uvwasi_##name* value)                 \
149
150#define READ_STRUCT(name)                                                     \
151  void uvwasi_serdes_read_##name(const void* ptr,                             \
152                                 size_t offset,                               \
153                                 uvwasi_##name* value)                        \
154
155#define WRITE_FIELD(field_offset, type, field)                                \
156  do {                                                                        \
157    uvwasi_serdes_write_##type(ptr, offset + field_offset, value->field);     \
158  } while (0)                                                                 \
159
160#define READ_FIELD(field_offset, type, field)                                 \
161  do {                                                                        \
162    value->field = uvwasi_serdes_read_##type(ptr, offset + field_offset);     \
163  } while (0)                                                                 \
164
165#define WRITE_ALIAS(new_name, old_name)                                       \
166  void uvwasi_serdes_write_##new_name(void* ptr,                              \
167                                      size_t offset,                          \
168                                      uvwasi_##new_name value) {              \
169    uvwasi_serdes_write_##old_name(ptr, offset, value);                       \
170  }                                                                           \
171
172#define READ_ALIAS(new_name, old_name)                                        \
173  uvwasi_##new_name uvwasi_serdes_read_##new_name(const void* ptr,            \
174                                                  size_t offset) {            \
175    return uvwasi_serdes_read_##old_name(ptr, offset);                        \
176  }                                                                           \
177
178ALL_TYPES(WRITE_STRUCT, WRITE_FIELD, WRITE_ALIAS)
179ALL_TYPES(READ_STRUCT, READ_FIELD, READ_ALIAS)
180
181
182uvwasi_errno_t uvwasi_serdes_read_ciovec_t(const void* ptr,
183                                           size_t end,
184                                           size_t offset,
185                                           uvwasi_ciovec_t* value) {
186  uint32_t buf_ptr;
187
188  buf_ptr = uvwasi_serdes_read_uint32_t(ptr, offset);
189  value->buf_len = uvwasi_serdes_read_size_t(ptr, offset + 4);
190
191  if (!uvwasi_serdes_check_bounds(buf_ptr, end, value->buf_len))
192    return UVWASI_EOVERFLOW;
193
194  value->buf = ((uint8_t*) ptr + buf_ptr);
195  return UVWASI_ESUCCESS;
196}
197
198
199uvwasi_errno_t uvwasi_serdes_read_iovec_t(const void* ptr,
200                                          size_t end,
201                                          size_t offset,
202                                          uvwasi_iovec_t* value) {
203  uint32_t buf_ptr;
204
205  buf_ptr = uvwasi_serdes_read_uint32_t(ptr, offset);
206  value->buf_len = uvwasi_serdes_read_size_t(ptr, offset + 4);
207
208  if (!uvwasi_serdes_check_bounds(buf_ptr, end, value->buf_len))
209    return UVWASI_EOVERFLOW;
210
211  value->buf = ((uint8_t*) ptr + buf_ptr);
212  return UVWASI_ESUCCESS;
213}
214
215
216uvwasi_errno_t uvwasi_serdes_readv_ciovec_t(const void* ptr,
217                                            size_t end,
218                                            size_t offset,
219                                            uvwasi_ciovec_t* iovs,
220                                            uvwasi_size_t iovs_len) {
221  uvwasi_errno_t err;
222  uvwasi_size_t i;
223
224  for (i = 0; i < iovs_len; i++) {
225    err = uvwasi_serdes_read_ciovec_t(ptr, end, offset, &iovs[i]);
226    if (err != UVWASI_ESUCCESS)
227      return err;
228    offset += UVWASI_SERDES_SIZE_ciovec_t;
229  }
230
231  return UVWASI_ESUCCESS;
232}
233
234
235uvwasi_errno_t uvwasi_serdes_readv_iovec_t(const void* ptr,
236                                           size_t end,
237                                           size_t offset,
238                                           uvwasi_iovec_t* iovs,
239                                           uvwasi_size_t iovs_len) {
240  uvwasi_errno_t err;
241  uvwasi_size_t i;
242
243  for (i = 0; i < iovs_len; i++) {
244    err = uvwasi_serdes_read_iovec_t(ptr, end, offset, &iovs[i]);
245    if (err != UVWASI_ESUCCESS)
246      return err;
247    offset += UVWASI_SERDES_SIZE_iovec_t;
248  }
249
250  return UVWASI_ESUCCESS;
251}
252
253
254int uvwasi_serdes_check_bounds(size_t offset, size_t end, size_t size) {
255  return end > offset && size <= (end - offset);
256}
257
258
259int uvwasi_serdes_check_array_bounds(size_t offset,
260                                     size_t end,
261                                     size_t size,
262                                     size_t count) {
263  return end > offset &&
264         ((count * size) / size == count) &&
265         (count * size <= end - offset);
266}
267