1 #include "wasi_serdes.h"
2 #include "wasi_types.h"
3
uvwasi_serdes_write_uint64_t(void * ptr,size_t offset,uint64_t value)4 void 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
uvwasi_serdes_write_uint32_t(void * ptr,size_t offset,uint32_t value)11 void 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
uvwasi_serdes_write_uint16_t(void * ptr,size_t offset,uint16_t value)18 void 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
uvwasi_serdes_write_uint8_t(void * ptr,size_t offset,uint8_t value)25 void uvwasi_serdes_write_uint8_t(void* ptr,
26 size_t offset,
27 uint8_t value) {
28 ((uint8_t*) ptr)[offset] = value;
29 }
30
uvwasi_serdes_read_uint64_t(const void * ptr,size_t offset)31 uint64_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
uvwasi_serdes_read_uint32_t(const void * ptr,size_t offset)37 uint32_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
uvwasi_serdes_read_uint16_t(const void * ptr,size_t offset)43 uint16_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
uvwasi_serdes_read_uint8_t(const void * ptr,size_t offset)49 uint8_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
ALL_TYPES(WRITE_STRUCT,WRITE_FIELD,WRITE_ALIAS)178 ALL_TYPES(WRITE_STRUCT, WRITE_FIELD, WRITE_ALIAS)
179 ALL_TYPES(READ_STRUCT, READ_FIELD, READ_ALIAS)
180
181
182 uvwasi_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
uvwasi_serdes_read_iovec_t(const void * ptr,size_t end,size_t offset,uvwasi_iovec_t * value)199 uvwasi_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
uvwasi_serdes_readv_ciovec_t(const void * ptr,size_t end,size_t offset,uvwasi_ciovec_t * iovs,uvwasi_size_t iovs_len)216 uvwasi_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
uvwasi_serdes_readv_iovec_t(const void * ptr,size_t end,size_t offset,uvwasi_iovec_t * iovs,uvwasi_size_t iovs_len)235 uvwasi_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
uvwasi_serdes_check_bounds(size_t offset,size_t end,size_t size)254 int uvwasi_serdes_check_bounds(size_t offset, size_t end, size_t size) {
255 return end > offset && size <= (end - offset);
256 }
257
258
uvwasi_serdes_check_array_bounds(size_t offset,size_t end,size_t size,size_t count)259 int 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