-
-
Notifications
You must be signed in to change notification settings - Fork 59
add serdes API #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
add serdes API #94
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5a04d29
add serdes API
tniessen 2e47796
Handle integer overflows in CHECK_ARRAY_BOUNDS
tniessen ed1204e
Rename 'size' to 'end' in bound checking macros
tniessen 9d1fd19
Adapt code style
tniessen 6e03032
Add scalar WASI types to serdes
tniessen 67338ae
Improve formatting of switch statement
tniessen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| #ifndef __UVWASI_SERDES_H__ | ||
| #define __UVWASI_SERDES_H__ | ||
|
|
||
| #include "wasi_types.h" | ||
|
|
||
| /* | ||
| Basic uint{8,16,32,64}_t read/write functions. | ||
| */ | ||
|
|
||
| #define BASIC_TYPE_(name, type) \ | ||
| void uvwasi_serdes_write_##name(void* ptr, size_t offset, type value); \ | ||
| type uvwasi_serdes_read_##name(const void* ptr, size_t offset); \ | ||
|
|
||
| #define BASIC_TYPE(type) BASIC_TYPE_(type, type) | ||
| #define BASIC_TYPE_UVWASI(type) BASIC_TYPE_(type, uvwasi_##type) | ||
|
|
||
| #define UVWASI_SERDES_SIZE_uint8_t sizeof(uint8_t) | ||
| BASIC_TYPE(uint8_t) | ||
| #define UVWASI_SERDES_SIZE_uint16_t sizeof(uint16_t) | ||
| BASIC_TYPE(uint16_t) | ||
| #define UVWASI_SERDES_SIZE_uint32_t sizeof(uint32_t) | ||
| BASIC_TYPE(uint32_t) | ||
| #define UVWASI_SERDES_SIZE_uint64_t sizeof(uint64_t) | ||
| BASIC_TYPE(uint64_t) | ||
|
|
||
| #define UVWASI_SERDES_SIZE_advice_t sizeof(uvwasi_advice_t) | ||
| BASIC_TYPE_UVWASI(advice_t) | ||
| #define UVWASI_SERDES_SIZE_clockid_t sizeof(uvwasi_clockid_t) | ||
| BASIC_TYPE_UVWASI(clockid_t) | ||
| #define UVWASI_SERDES_SIZE_device_t sizeof(uvwasi_device_t) | ||
| BASIC_TYPE_UVWASI(device_t) | ||
| #define UVWASI_SERDES_SIZE_dircookie_t sizeof(uvwasi_dircookie_t) | ||
| BASIC_TYPE_UVWASI(dircookie_t) | ||
| #define UVWASI_SERDES_SIZE_eventrwflags_t sizeof(uvwasi_eventrwflags_t) | ||
| BASIC_TYPE_UVWASI(eventrwflags_t) | ||
| #define UVWASI_SERDES_SIZE_eventtype_t sizeof(uvwasi_eventtype_t) | ||
| BASIC_TYPE_UVWASI(eventtype_t) | ||
| #define UVWASI_SERDES_SIZE_exitcode_t sizeof(uvwasi_exitcode_t) | ||
| BASIC_TYPE_UVWASI(exitcode_t) | ||
| #define UVWASI_SERDES_SIZE_fd_t sizeof(uvwasi_fd_t) | ||
| BASIC_TYPE_UVWASI(fd_t) | ||
| #define UVWASI_SERDES_SIZE_fdflags_t sizeof(uvwasi_fdflags_t) | ||
| BASIC_TYPE_UVWASI(fdflags_t) | ||
| #define UVWASI_SERDES_SIZE_filesize_t sizeof(uvwasi_filesize_t) | ||
| BASIC_TYPE_UVWASI(filesize_t) | ||
| #define UVWASI_SERDES_SIZE_fstflags_t sizeof(uvwasi_fstflags_t) | ||
| BASIC_TYPE_UVWASI(fstflags_t) | ||
| #define UVWASI_SERDES_SIZE_inode_t sizeof(uvwasi_inode_t) | ||
| BASIC_TYPE_UVWASI(inode_t) | ||
| #define UVWASI_SERDES_SIZE_linkcount_t sizeof(uvwasi_linkcount_t) | ||
| BASIC_TYPE_UVWASI(linkcount_t) | ||
| #define UVWASI_SERDES_SIZE_lookupflags_t sizeof(uvwasi_lookupflags_t) | ||
| BASIC_TYPE_UVWASI(lookupflags_t) | ||
| #define UVWASI_SERDES_SIZE_oflags_t sizeof(uvwasi_oflags_t) | ||
| BASIC_TYPE_UVWASI(oflags_t) | ||
| #define UVWASI_SERDES_SIZE_preopentype_t sizeof(uvwasi_preopentype_t) | ||
| BASIC_TYPE_UVWASI(preopentype_t) | ||
| #define UVWASI_SERDES_SIZE_riflags_t sizeof(uvwasi_riflags_t) | ||
| BASIC_TYPE_UVWASI(riflags_t) | ||
| #define UVWASI_SERDES_SIZE_rights_t sizeof(uvwasi_rights_t) | ||
| BASIC_TYPE_UVWASI(rights_t) | ||
| #define UVWASI_SERDES_SIZE_roflags_t sizeof(uvwasi_roflags_t) | ||
| BASIC_TYPE_UVWASI(roflags_t) | ||
| #define UVWASI_SERDES_SIZE_sdflags_t sizeof(uvwasi_sdflags_t) | ||
| BASIC_TYPE_UVWASI(sdflags_t) | ||
| #define UVWASI_SERDES_SIZE_siflags_t sizeof(uvwasi_siflags_t) | ||
| BASIC_TYPE_UVWASI(siflags_t) | ||
| #define UVWASI_SERDES_SIZE_inode_t sizeof(uvwasi_inode_t) | ||
| BASIC_TYPE_UVWASI(inode_t) | ||
| #define UVWASIS_SERDES_SIZE_signal_t sizeof(uvwasi_signal_t) | ||
| BASIC_TYPE_UVWASI(signal_t) | ||
| #define UVWASIS_SERDES_SIZE_subclockflags_t sizeof(uvwasi_subclockflags_t) | ||
| BASIC_TYPE_UVWASI(subclockflags_t) | ||
| #define UVWASIS_SERDES_SIZE_timestamp_t sizeof(uvwasi_timestamp_t) | ||
| BASIC_TYPE_UVWASI(timestamp_t) | ||
| #define UVWASIS_SERDES_SIZE_userdata_t sizeof(uvwasi_userdata_t) | ||
| BASIC_TYPE_UVWASI(userdata_t) | ||
| #define UVWASIS_SERDES_SIZE_whence_t sizeof(uvwasi_whence_t) | ||
| BASIC_TYPE_UVWASI(whence_t) | ||
|
|
||
| #undef BASIC_TYPE_UVWASI | ||
| #undef BASIC_TYPE | ||
| #undef BASIC_TYPE_ | ||
|
|
||
| /* | ||
| WASI structure read/write functions. | ||
| */ | ||
|
|
||
| #define STRUCT(name) \ | ||
| void uvwasi_serdes_write_##name(void* ptr, \ | ||
| size_t offset, \ | ||
| const uvwasi_##name* value); \ | ||
| void uvwasi_serdes_read_##name(const void* ptr, \ | ||
| size_t offset, \ | ||
| uvwasi_##name* value); \ | ||
|
|
||
| #define UVWASI_SERDES_SIZE_fdstat_t 24 | ||
| STRUCT(fdstat_t) | ||
|
|
||
| #define UVWASI_SERDES_SIZE_filestat_t 64 | ||
| STRUCT(filestat_t) | ||
|
|
||
| #define UVWASI_SERDES_SIZE_prestat_t 8 | ||
| STRUCT(prestat_t) | ||
|
|
||
| #define UVWASI_SERDES_SIZE_event_t 32 | ||
| STRUCT(event_t) | ||
|
bnoordhuis marked this conversation as resolved.
|
||
|
|
||
| #define UVWASI_SERDES_SIZE_subscription_t 48 | ||
| STRUCT(subscription_t) | ||
|
|
||
| #undef STRUCT | ||
|
|
||
| /* | ||
| Helper macros for bound checking. | ||
| */ | ||
|
|
||
| #define UVWASI_SERDES_CHECK_BOUNDS(offset, end, type) \ | ||
| ((offset) >= 0 && \ | ||
| (end) > (offset) && \ | ||
| (UVWASI_SERDES_SIZE_##type <= (end) - (offset))) \ | ||
|
|
||
| #define UVWASI_SERDES_CHECK_ARRAY_BOUNDS(offset, end, type, count) \ | ||
| ((offset) >= 0 && \ | ||
| (end) > (offset) && \ | ||
| (count) >= 0 && \ | ||
| ((count) * UVWASI_SERDES_SIZE_##type) / UVWASI_SERDES_SIZE_##type == \ | ||
| (count) && \ | ||
| ((count) * UVWASI_SERDES_SIZE_##type <= (end) - (offset))) \ | ||
|
|
||
| #endif /* __UVWASI_SERDES_H__ */ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| #include "uvwasi.h" | ||
|
|
||
| inline void uvwasi_serdes_write_uint64_t(void* ptr, | ||
| size_t offset, | ||
| uint64_t value) { | ||
| uvwasi_serdes_write_uint32_t(ptr, offset, (uint32_t) value); | ||
| uvwasi_serdes_write_uint32_t(ptr, offset + 4, value >> 32); | ||
| } | ||
|
|
||
| inline void uvwasi_serdes_write_uint32_t(void* ptr, | ||
| size_t offset, | ||
| uint32_t value) { | ||
| uvwasi_serdes_write_uint16_t(ptr, offset, (uint16_t) value); | ||
| uvwasi_serdes_write_uint16_t(ptr, offset + 2, value >> 16); | ||
| } | ||
|
|
||
| inline void uvwasi_serdes_write_uint16_t(void* ptr, | ||
| size_t offset, | ||
| uint16_t value) { | ||
| uvwasi_serdes_write_uint8_t(ptr, offset, (uint8_t) value); | ||
| uvwasi_serdes_write_uint8_t(ptr, offset + 1, value >> 8); | ||
| } | ||
|
|
||
| inline void uvwasi_serdes_write_uint8_t(void* ptr, | ||
| size_t offset, | ||
| uint8_t value) { | ||
| ((uint8_t*) ptr)[offset] = value; | ||
| } | ||
|
|
||
| inline uint64_t uvwasi_serdes_read_uint64_t(const void* ptr, size_t offset) { | ||
| uint64_t low = uvwasi_serdes_read_uint32_t(ptr, offset); | ||
| uint64_t high = uvwasi_serdes_read_uint32_t(ptr, offset + 4); | ||
| return low | (high << 32); | ||
| } | ||
|
|
||
| inline uint32_t uvwasi_serdes_read_uint32_t(const void* ptr, size_t offset) { | ||
| uint32_t low = uvwasi_serdes_read_uint16_t(ptr, offset); | ||
| uint32_t high = uvwasi_serdes_read_uint16_t(ptr, offset + 2); | ||
| return low | (high << 16); | ||
| } | ||
|
|
||
| inline uint16_t uvwasi_serdes_read_uint16_t(const void* ptr, size_t offset) { | ||
| uint16_t low = uvwasi_serdes_read_uint8_t(ptr, offset); | ||
| uint16_t high = uvwasi_serdes_read_uint8_t(ptr, offset + 1); | ||
| return low | (high << 8); | ||
| } | ||
|
|
||
| inline uint8_t uvwasi_serdes_read_uint8_t(const void* ptr, size_t offset) { | ||
| return ((const uint8_t*) ptr)[offset]; | ||
| } | ||
|
|
||
| #define TYPE_SWITCH switch (value->type) | ||
|
|
||
| #define ALL_TYPES(STRUCT, FIELD, ALIAS) \ | ||
| \ | ||
| ALIAS(advice_t, uint8_t) \ | ||
| ALIAS(clockid_t, uint32_t) \ | ||
| ALIAS(device_t, uint64_t) \ | ||
| ALIAS(dircookie_t, uint64_t) \ | ||
| ALIAS(errno_t, uint16_t) \ | ||
| ALIAS(eventrwflags_t, uint16_t) \ | ||
| ALIAS(eventtype_t, uint8_t) \ | ||
| ALIAS(exitcode_t, uint32_t) \ | ||
| ALIAS(fd_t, uint32_t) \ | ||
| ALIAS(fdflags_t, uint16_t) \ | ||
| ALIAS(filesize_t, uint64_t) \ | ||
| ALIAS(filetype_t, uint8_t) \ | ||
| ALIAS(fstflags_t, uint16_t) \ | ||
| ALIAS(inode_t, uint64_t) \ | ||
| ALIAS(linkcount_t, uint64_t) \ | ||
| ALIAS(lookupflags_t, uint32_t) \ | ||
| ALIAS(oflags_t, uint16_t) \ | ||
| ALIAS(preopentype_t, uint8_t) \ | ||
| ALIAS(riflags_t, uint16_t) \ | ||
| ALIAS(rights_t, uint64_t) \ | ||
| ALIAS(roflags_t, uint16_t) \ | ||
| ALIAS(sdflags_t, uint8_t) \ | ||
| ALIAS(siflags_t, uint16_t) \ | ||
| ALIAS(signal_t, uint8_t) \ | ||
| ALIAS(subclockflags_t, uint16_t) \ | ||
| ALIAS(timestamp_t, uint64_t) \ | ||
| ALIAS(userdata_t, uint64_t) \ | ||
| ALIAS(whence_t, uint8_t) \ | ||
| \ | ||
| STRUCT(fdstat_t) { \ | ||
| FIELD( 0, filetype_t, fs_filetype); \ | ||
| FIELD( 2, fdflags_t, fs_flags); \ | ||
| FIELD( 8, rights_t, fs_rights_base); \ | ||
| FIELD(16, rights_t, fs_rights_inheriting); \ | ||
| } \ | ||
| \ | ||
| STRUCT(filestat_t) { \ | ||
| FIELD( 0, device_t, st_dev); \ | ||
| FIELD( 8, inode_t, st_ino); \ | ||
| FIELD(16, filetype_t, st_filetype); \ | ||
| FIELD(24, linkcount_t, st_nlink); \ | ||
| FIELD(32, filesize_t, st_size); \ | ||
| FIELD(40, timestamp_t, st_atim); \ | ||
| FIELD(48, timestamp_t, st_mtim); \ | ||
| FIELD(56, timestamp_t, st_ctim); \ | ||
| } \ | ||
| \ | ||
| STRUCT(prestat_t) { \ | ||
| FIELD(0, preopentype_t, pr_type); \ | ||
| FIELD(4, uint32_t, u.dir.pr_name_len); \ | ||
| } \ | ||
| \ | ||
| STRUCT(event_t) { \ | ||
| FIELD( 0, userdata_t, userdata); \ | ||
| FIELD( 8, errno_t, error); \ | ||
| FIELD(10, eventtype_t, type); \ | ||
| TYPE_SWITCH { \ | ||
| case UVWASI_EVENTTYPE_FD_READ: \ | ||
| case UVWASI_EVENTTYPE_FD_WRITE: \ | ||
| FIELD(16, filesize_t, u.fd_readwrite.nbytes); \ | ||
| FIELD(24, eventrwflags_t, u.fd_readwrite.flags); \ | ||
| } \ | ||
| } \ | ||
| \ | ||
| STRUCT(subscription_t) { \ | ||
| FIELD(0, userdata_t, userdata); \ | ||
| FIELD(8, eventtype_t, type); \ | ||
| TYPE_SWITCH { \ | ||
| case UVWASI_EVENTTYPE_CLOCK: \ | ||
| FIELD(16, clockid_t, u.clock.clock_id); \ | ||
| FIELD(24, timestamp_t, u.clock.timeout); \ | ||
| FIELD(32, timestamp_t, u.clock.precision); \ | ||
| FIELD(40, subclockflags_t, u.clock.flags); \ | ||
| break; \ | ||
| case UVWASI_EVENTTYPE_FD_READ: \ | ||
| case UVWASI_EVENTTYPE_FD_WRITE: \ | ||
| FIELD(16, fd_t, u.fd_readwrite.fd); \ | ||
| } \ | ||
| } \ | ||
|
|
||
| #define WRITE_STRUCT(name) \ | ||
| void uvwasi_serdes_write_##name(void* ptr, \ | ||
| size_t offset, \ | ||
| const uvwasi_##name* value) \ | ||
|
|
||
| #define READ_STRUCT(name) \ | ||
| void uvwasi_serdes_read_##name(const void* ptr, \ | ||
| size_t offset, \ | ||
| uvwasi_##name* value) \ | ||
|
|
||
| #define WRITE_FIELD(field_offset, type, field) \ | ||
| do { \ | ||
| uvwasi_serdes_write_##type(ptr, offset + field_offset, value->field); \ | ||
| } while (0) \ | ||
|
|
||
| #define READ_FIELD(field_offset, type, field) \ | ||
| do { \ | ||
| value->field = uvwasi_serdes_read_##type(ptr, offset + field_offset); \ | ||
| } while (0) \ | ||
|
|
||
| #define WRITE_ALIAS(new_name, old_name) \ | ||
| void uvwasi_serdes_write_##new_name(void* ptr, \ | ||
| size_t offset, \ | ||
| uvwasi_##new_name value) { \ | ||
| uvwasi_serdes_write_##old_name(ptr, offset, value); \ | ||
| } \ | ||
|
|
||
| #define READ_ALIAS(new_name, old_name) \ | ||
| uvwasi_##new_name uvwasi_serdes_read_##new_name(const void* ptr, \ | ||
| size_t offset) { \ | ||
| return uvwasi_serdes_read_##old_name(ptr, offset); \ | ||
| } \ | ||
|
|
||
| ALL_TYPES(WRITE_STRUCT, WRITE_FIELD, WRITE_ALIAS) | ||
| ALL_TYPES(READ_STRUCT, READ_FIELD, READ_ALIAS) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UVWASI_SERDES_SIZE_prestat_tdoesn't look correct to me. I see that you're serializingu.dir.pr_name_lenas auint32_tbut its type issize_t(i.e., 64 bits on 64 bits architectures.)I suppose that realistically it always fits in a
uint32_tbut I'd still add some kind of range check.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused about this part myself. WASI requires it to be a
size_t, but I am not sure if that's a host typesize_tor a WASM typesize_t. Node.js currently uses 32 bits.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with 32 bits because that's what the wasi-libc did here.
Also, according to this ABI doc,
size_tis defined asunsigned long, which has asizeoffour, and is represented as a wasm i32.