diff options
author | Andy Wingo <wingo@pobox.com> | 2016-04-19 22:58:33 +0200 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-04-19 22:58:33 +0200 |
commit | bb6edc5a35c570b3355dd69f89cbc8d0f85fc21c (patch) | |
tree | 35e4de3e947623336cd533775767b431b28bf7ac /libguile/ports-internal.h | |
parent | ffb4347d5330fbd2b3e78d761613955f83aeef3d (diff) | |
download | guile-bb6edc5a35c570b3355dd69f89cbc8d0f85fc21c.tar.gz |
peek-u8 correctness and speed refactor
* libguile/ports-internal.h (scm_port_buffer_size): Verify that the
bytevector field is a bytevector, in anticipation of Schemification.
(scm_port_buffer_can_take, scm_port_buffer_can_put)
(scm_port_buffer_can_putback): Enforce invariants on cur and end
here.
(scm_port_buffer_did_take, scm_port_buffer_did_put): Relax to not call
other functions.
* libguile/ports.h (scm_get_byte_or_eof_unlocked)
(scm_peek_byte_or_eof_unlocked): Refactor to call no functions on the
fast path.
Diffstat (limited to 'libguile/ports-internal.h')
-rw-r--r-- | libguile/ports-internal.h | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/libguile/ports-internal.h b/libguile/ports-internal.h index 862d85800..a8c4ea93b 100644 --- a/libguile/ports-internal.h +++ b/libguile/ports-internal.h @@ -27,10 +27,26 @@ #include "libguile/_scm.h" #include "libguile/ports.h" +/* The port buffers are exposed to Scheme, which can mutate their + fields. We have to do dynamic checks to ensure that + potentially-malicious Scheme doesn't invalidate our invariants. + However these dynamic checks are slow, so we need to avoid them where + they are unnecessary. An unnecessary check is a check which has + already been performed, or one which would already be performed by + the time that memory is accessed. Given that the "can_take", + "can_put", or "can_putback" functions are eventually called before + any access to the buffer, we hoist the necessary type checks the + can_foo and size functions, and otherwise assume that the cur and end + values are inums within the right ranges. */ + static inline size_t scm_port_buffer_size (scm_t_port_buffer *buf) { - return scm_c_bytevector_length (buf->bytevector); + if (SCM_LIKELY (SCM_BYTEVECTOR_P (buf->bytevector))) + return SCM_BYTEVECTOR_LENGTH (buf->bytevector); + scm_misc_error (NULL, "invalid port buffer ~a", + scm_list_1 (buf->bytevector)); + return -1; } static inline void @@ -48,31 +64,45 @@ scm_port_buffer_reset_end (scm_t_port_buffer *buf) static inline size_t scm_port_buffer_can_take (scm_t_port_buffer *buf) { - return scm_to_size_t (buf->end) - scm_to_size_t (buf->cur); + size_t cur, end; + cur = scm_to_size_t (buf->cur); + end = scm_to_size_t (buf->end); + if (cur > end || end > scm_port_buffer_size (buf)) + scm_misc_error (NULL, "invalid port buffer cursors ~a, ~a", + scm_list_2 (buf->cur, buf->end)); + return end - cur; } static inline size_t scm_port_buffer_can_put (scm_t_port_buffer *buf) { - return scm_port_buffer_size (buf) - scm_to_size_t (buf->end); + size_t end = scm_to_size_t (buf->end); + if (end > scm_port_buffer_size (buf)) + scm_misc_error (NULL, "invalid port buffer cursor ~a", + scm_list_1 (buf->end)); + return scm_port_buffer_size (buf) - end; } static inline size_t scm_port_buffer_can_putback (scm_t_port_buffer *buf) { - return scm_to_size_t (buf->cur); + size_t cur = scm_to_size_t (buf->cur); + if (cur > scm_port_buffer_size (buf)) + scm_misc_error (NULL, "invalid port buffer cursor ~a", + scm_list_1 (buf->cur)); + return cur; } static inline void scm_port_buffer_did_take (scm_t_port_buffer *buf, size_t count) { - buf->cur = scm_from_size_t (scm_to_size_t (buf->cur) + count); + buf->cur = SCM_I_MAKINUM (SCM_I_INUM (buf->cur) + count); } static inline void scm_port_buffer_did_put (scm_t_port_buffer *buf, size_t count) { - buf->end = scm_from_size_t (scm_to_size_t (buf->end) + count); + buf->end = SCM_I_MAKINUM (SCM_I_INUM (buf->end) + count); } static inline const scm_t_uint8 * |