Skip to content
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

refactor: optimize read_register to read to non-zeroed buffer #804

Merged
merged 7 commits into from
May 20, 2022

Conversation

austinabell
Copy link
Contributor

@austinabell austinabell commented Apr 28, 2022

Removed need to zero out the buffer before writing to it, seems it would be an impactful optimization.

The only opinionated point is if conversion from u64 to usize (u32 in wasm32) should be checked or not. The maximum buffer size in configs in the runtime is less than u32::MAX but there doesn't seem to be any blockers from this changing with a custom config -- potentially this should be unchecked for a trivial optimization in code size? The only issue is that there is UB if the register length is > u32::MAX because the buffer created wouldn't be large enough and memory would be written outside of the buffer. cc @matklad will there be any guarantee that the max will always be < u32::MAX?

@matklad
Copy link
Contributor

matklad commented May 11, 2022

cc @matklad will there be any guarantee that the max will always be < u32::MAX?

I think yes, this is guaranteed, by both the config and by fees. But I think the current impl with .unwrap_or_abort() is the best option -- better safe than unsafe, and I doubt that it'll increase the code size a lot.

Comment on lines 118 to 121
// Get register length and convert to a usize. The max register size in config is much less
// than the u32 max so the abort should never be hit, but is there for safety because there
// would be undefined behaviour if the case would be hit.
let len: usize = register_len(register_id)?.try_into().unwrap_or_else(|_| abort());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really undefined behavior though? From the docs, casting just truncates:

Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will truncate

but it's not ideal either for us to have a truncated len either, so the change still seems valid to me

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UB would happen not during truncation, but when the runtime writes past the truncated lenght.

Copy link
Contributor Author

@austinabell austinabell May 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as Aleksey mentions, this is just used to set the capacity of the buffer. When the write happens with read_register, it will write past the buffer, because the length is truncated, into other parts of memory (UB).

But yeah I suppose the doc comment could be more explicit to mention that the UB would happen on a later line than this one

Edit: new wording "would be undefined behaviour during read_register if the buffer length is truncated." hopefully that is more clear!

@austinabell austinabell merged commit 99174aa into master May 20, 2022
@austinabell austinabell deleted the austin/register_optimize branch May 20, 2022 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants