Line data Source code
1 : #ifndef HEADER_src_ballet_tls_fd_tls_serde_h 2 : #define HEADER_src_ballet_tls_fd_tls_serde_h 3 : 4 : /* fd_tls_serde.h provides branch-minimizing (de-)serializer macros for 5 : internal use. This file specifically exists for fd_tls_proto.c and 6 : should not be included elsewhere. */ 7 : 8 : /* FD_TLS_SERDE_{BEGIN,END} create and terminate a bounds checking 9 : context. Internally, creates a new do/while(0) scope. */ 10 : 11 : #include "fd_tls_proto.h" 12 313170 : #define FD_TLS_SERDE_BEGIN do { \ 13 313170 : int valid = 1; \ 14 : 15 313170 : #define FD_TLS_SERDE_END } while(0); 16 : 17 : /* FD_TLS_SERDE_LOCATE defines a local variable pointing to the would- 18 : be position of the field to be decoded, which may be out-of-bounds. 19 : Also extends the "valid" expression to include a bounds check for 20 : this field. Both the "valid" expression and this local can be fully 21 : constant-propagated if sz is constant. */ 22 : 23 : #define FD_TLS_SERDE_LOCATE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 24 855021 : ulong _field_##IDX##_laddr = wire_laddr; \ 25 855021 : ulong const _field_##IDX##_cnt = (FIELD_CNT); \ 26 855021 : ulong const _field_##IDX##_sz = sizeof(FIELD_TYPE)*_field_##IDX##_cnt; \ 27 855021 : valid &= (wire_sz >= _field_##IDX##_sz); \ 28 855021 : wire_sz -= _field_##IDX##_sz; \ 29 855021 : wire_laddr += _field_##IDX##_sz; 30 : 31 : /* FD_TLS_SERDE_CHECK performs tbe bounds checks queued by prior 32 : FD_TLS_SERDE_LOCATE ops. */ 33 : 34 : #define FD_TLS_SERDE_CHECK \ 35 349284 : if( FD_UNLIKELY( !valid ) ) return -(long)FD_TLS_ALERT_DECODE_ERROR; 36 : 37 : /* FD_TLS_SERDE_DECODE generates a non-overlapping memory copy for the 38 : given field. Field should be bounds checked at this point. 39 : 40 : Note: We use __extension__ here because ISO C forbids casting a 41 : non-scalar type to itself. (as is the case with tls_u24). */ 42 : 43 : #define FD_TLS_SERDE_DECODE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 44 397524 : do { \ 45 397524 : memcpy( (FIELD), (void const *)_field_##IDX##_laddr, _field_##IDX##_sz ); \ 46 397524 : FIELD_TYPE * _field_##IDX##_ptr = (FIELD); \ 47 1547670 : for( ulong i=0; i < (FIELD_CNT); i++ ) { \ 48 1150146 : *((_field_##IDX##_ptr)++) = __extension__ \ 49 1150146 : (FIELD_TYPE)fd_##FIELD_TYPE##_bswap( (FIELD)[i] ); \ 50 1150146 : } \ 51 397524 : } while(0); 52 : 53 : #define FD_TLS_SERDE_ENCODE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 54 421383 : do { \ 55 421383 : uchar * dest = (uchar *)_field_##IDX##_laddr; \ 56 421383 : memcpy( dest, (FIELD), _field_##IDX##_sz ); \ 57 421383 : FIELD_TYPE * ele = fd_type_pun( dest ); \ 58 2906979 : for( ulong i=0; i<(FIELD_CNT); i++ ) { \ 59 2485596 : *ele = fd_##FIELD_TYPE##_bswap( *ele ); \ 60 2485596 : ele++; \ 61 2485596 : } \ 62 421383 : } while(0); 63 : 64 : /* FD_TLS_DECODE_FIELD is a convenience macro for decoding a single 65 : field with known size. */ 66 : 67 : #define FD_TLS_DECODE_FIELD( FIELD, FIELD_TYPE ) \ 68 126516 : FD_TLS_SERDE_BEGIN \ 69 126516 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \ 70 126516 : FD_TLS_SERDE_CHECK \ 71 126516 : FD_TLS_SERDE_DECODE( _, FIELD, FIELD_TYPE, 1 ) \ 72 126516 : FD_TLS_SERDE_END 73 : 74 : #define FD_TLS_ENCODE_FIELD( FIELD, FIELD_TYPE ) \ 75 0 : FD_TLS_SERDE_BEGIN \ 76 0 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \ 77 0 : FD_TLS_SERDE_CHECK \ 78 0 : FD_TLS_SERDE_ENCODE( _, FIELD, FIELD_TYPE, 1 ) \ 79 0 : FD_TLS_SERDE_END 80 : 81 : /* FD_TLS_DECODE_STATIC_BATCH is a convenience macro for decoding a 82 : batch of static sized fields in a new decode context. */ 83 : 84 : #define FD_TLS_DECODE_STATIC_BATCH( fields ) \ 85 120447 : FD_TLS_SERDE_BEGIN \ 86 271008 : fields( FD_TLS_SERDE_LOCATE ) \ 87 120447 : FD_TLS_SERDE_CHECK \ 88 271008 : fields( FD_TLS_SERDE_DECODE ) \ 89 120447 : FD_TLS_SERDE_END 90 : 91 : #define FD_TLS_ENCODE_STATIC_BATCH( fields ) \ 92 66207 : FD_TLS_SERDE_BEGIN \ 93 421383 : fields( FD_TLS_SERDE_LOCATE ) \ 94 66207 : FD_TLS_SERDE_CHECK \ 95 421383 : fields( FD_TLS_SERDE_ENCODE ) \ 96 66207 : FD_TLS_SERDE_END 97 : 98 : #define FD_TLS_DECODE_LIST_BEGIN( LIST_SZ_TYPE, ALIGN ) \ 99 60228 : do { \ 100 60228 : LIST_SZ_TYPE list_sz; \ 101 60228 : FD_TLS_DECODE_FIELD( &list_sz, LIST_SZ_TYPE ); \ 102 60228 : if( FD_UNLIKELY( !fd_ulong_is_aligned( list_sz, (ALIGN) ) ) ) \ 103 60228 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 104 60228 : if( FD_UNLIKELY( list_sz > wire_sz ) ) \ 105 60228 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 106 60228 : ulong const list_start = wire_laddr; \ 107 60228 : ulong const list_stop = list_start + list_sz; \ 108 198795 : while( wire_laddr < list_stop ) \ 109 : 110 : #define FD_TLS_DECODE_LIST_END \ 111 60228 : if( FD_UNLIKELY( wire_laddr != list_stop ) ) \ 112 60228 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 113 60228 : } while(0); \ 114 : 115 30096 : #define FD_TLS_SKIP_FIELD( FIELD_TYPE ) (__extension__({ \ 116 30096 : int valid = 1; \ 117 30096 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, 1 ) \ 118 30096 : FD_TLS_SERDE_CHECK \ 119 30096 : (FIELD_TYPE *)fd_type_pun( (void *)_field__laddr ); \ 120 30096 : })) 121 : 122 6018 : #define FD_TLS_SKIP_FIELDS( FIELD_TYPE, CNT ) (__extension__({ \ 123 6018 : int valid = 1; \ 124 6018 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, (CNT) ) \ 125 6018 : FD_TLS_SERDE_CHECK \ 126 6018 : (FIELD_TYPE *)_field__laddr; \ 127 6018 : })) 128 : 129 6024 : #define FD_TLS_DECODE_SUB( FUNC, OUT ) do { \ 130 6024 : long res = FUNC( (OUT), (void const *)wire_laddr, wire_sz ); \ 131 6024 : if( FD_UNLIKELY( res<0L ) ) return res; \ 132 6024 : wire_laddr += (ulong)res; \ 133 6024 : wire_sz -= (ulong)res; \ 134 6024 : } while(0) 135 : 136 24060 : #define FD_TLS_ENCODE_SUB( FUNC, IN ) (__extension__({ \ 137 24060 : long res = FUNC( (IN), (void *)wire_laddr, wire_sz ); \ 138 24060 : if( FD_UNLIKELY( res<0L ) ) return res; \ 139 24060 : wire_laddr += (ulong)res; \ 140 24060 : wire_sz -= (ulong)res; \ 141 24060 : (ulong)res; \ 142 24060 : })) 143 : 144 : #endif /* HEADER_src_ballet_tls_fd_tls_serde_h */