Line data Source code
1 : #ifndef HEADER_fd_src_waltz_tls_fd_tls_serde_h 2 : #define HEADER_fd_src_waltz_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 256137 : #define FD_TLS_SERDE_BEGIN do { \ 13 256137 : int valid = 1; \ 14 : 15 256137 : #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 792540 : ulong _field_##IDX##_laddr = wire_laddr; \ 25 792540 : ulong const _field_##IDX##_cnt = (FIELD_CNT); \ 26 792540 : ulong const _field_##IDX##_sz = sizeof(FIELD_TYPE)*_field_##IDX##_cnt; \ 27 792540 : valid &= (wire_sz >= _field_##IDX##_sz); \ 28 792540 : wire_sz -= _field_##IDX##_sz; \ 29 792540 : wire_laddr += _field_##IDX##_sz; 30 : 31 : /* FD_TLS_SERDE_CHECK performs the bounds checks queued by prior 32 : FD_TLS_SERDE_LOCATE ops. */ 33 : 34 : #define FD_TLS_SERDE_CHECK \ 35 317070 : 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 335313 : do { \ 45 335313 : memcpy( (FIELD), (void const *)_field_##IDX##_laddr, _field_##IDX##_sz ); \ 46 335313 : FIELD_TYPE * _field_##IDX##_ptr = (FIELD); \ 47 1814412 : for( ulong i=0; i < (FIELD_CNT); i++ ) { \ 48 1479099 : *((_field_##IDX##_ptr)++) = __extension__ \ 49 1479099 : (FIELD_TYPE)fd_##FIELD_TYPE##_bswap( (FIELD)[i] ); \ 50 1479099 : } \ 51 335313 : } while(0); 52 : 53 : #define FD_TLS_SERDE_ENCODE( IDX, FIELD, FIELD_TYPE, FIELD_CNT ) \ 54 396294 : do { \ 55 396294 : uchar * dest = (uchar *)_field_##IDX##_laddr; \ 56 396294 : memcpy( dest, (FIELD), _field_##IDX##_sz ); \ 57 6000093 : for( ulong i=0; i<(FIELD_CNT); i++ ) { \ 58 5603799 : FIELD_TYPE temp; \ 59 5603799 : memcpy( &temp, dest, sizeof(FIELD_TYPE) ); \ 60 5603799 : temp = fd_##FIELD_TYPE##_bswap( temp ); \ 61 5603799 : memcpy( dest, &temp, sizeof(FIELD_TYPE) ); \ 62 5603799 : dest += sizeof(FIELD_TYPE); \ 63 5603799 : } \ 64 396294 : } while(0); 65 : 66 : /* FD_TLS_DECODE_FIELD is a convenience macro for decoding a single 67 : field with known size. */ 68 : 69 : #define FD_TLS_DECODE_FIELD( FIELD, FIELD_TYPE ) \ 70 91647 : FD_TLS_SERDE_BEGIN \ 71 91647 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \ 72 91647 : FD_TLS_SERDE_CHECK \ 73 91647 : FD_TLS_SERDE_DECODE( _, FIELD, FIELD_TYPE, 1 ) \ 74 91647 : FD_TLS_SERDE_END 75 : 76 : #define FD_TLS_ENCODE_FIELD( FIELD, FIELD_TYPE ) \ 77 0 : FD_TLS_SERDE_BEGIN \ 78 0 : FD_TLS_SERDE_LOCATE( _, FIELD, FIELD_TYPE, 1 ) \ 79 0 : FD_TLS_SERDE_CHECK \ 80 0 : FD_TLS_SERDE_ENCODE( _, FIELD, FIELD_TYPE, 1 ) \ 81 0 : FD_TLS_SERDE_END 82 : 83 : /* FD_TLS_DECODE_STATIC_BATCH is a convenience macro for decoding a 84 : batch of static sized fields in a new decode context. */ 85 : 86 : #define FD_TLS_DECODE_STATIC_BATCH( fields ) \ 87 103575 : FD_TLS_SERDE_BEGIN \ 88 243666 : fields( FD_TLS_SERDE_LOCATE ) \ 89 103575 : FD_TLS_SERDE_CHECK \ 90 243666 : fields( FD_TLS_SERDE_DECODE ) \ 91 103575 : FD_TLS_SERDE_END 92 : 93 : #define FD_TLS_ENCODE_STATIC_BATCH( fields ) \ 94 60915 : FD_TLS_SERDE_BEGIN \ 95 396294 : fields( FD_TLS_SERDE_LOCATE ) \ 96 60915 : FD_TLS_SERDE_CHECK \ 97 396294 : fields( FD_TLS_SERDE_ENCODE ) \ 98 60915 : FD_TLS_SERDE_END 99 : 100 : #define FD_TLS_DECODE_LIST_BEGIN( LIST_SZ_TYPE, ALIGN ) \ 101 48732 : do { \ 102 48732 : LIST_SZ_TYPE list_sz; \ 103 48732 : FD_TLS_DECODE_FIELD( &list_sz, LIST_SZ_TYPE ); \ 104 48732 : if( FD_UNLIKELY( !fd_ulong_is_aligned( list_sz, (ALIGN) ) ) ) \ 105 48732 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 106 48732 : if( FD_UNLIKELY( list_sz > wire_sz ) ) \ 107 48732 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 108 48732 : ulong const list_start = wire_laddr; \ 109 48732 : ulong const list_stop = list_start + list_sz; \ 110 140454 : while( wire_laddr < list_stop ) \ 111 : 112 : #define FD_TLS_DECODE_LIST_END \ 113 48732 : if( FD_UNLIKELY( wire_laddr != list_stop ) ) \ 114 48732 : return -(long)FD_TLS_ALERT_DECODE_ERROR; \ 115 48732 : } while(0); \ 116 : 117 48750 : #define FD_TLS_SKIP_FIELD( FIELD_TYPE ) (__extension__({ \ 118 48750 : int valid = 1; \ 119 48750 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, 1 ) \ 120 48750 : FD_TLS_SERDE_CHECK \ 121 48750 : (FIELD_TYPE *)fd_type_pun( (void *)_field__laddr ); \ 122 48723 : })) 123 : 124 12183 : #define FD_TLS_SKIP_FIELDS( FIELD_TYPE, CNT ) (__extension__({ \ 125 12183 : int valid = 1; \ 126 12183 : FD_TLS_SERDE_LOCATE( , , FIELD_TYPE, (CNT) ) \ 127 12183 : FD_TLS_SERDE_CHECK \ 128 12183 : (FIELD_TYPE *)_field__laddr; \ 129 12183 : })) 130 : 131 6093 : #define FD_TLS_DECODE_SUB( FUNC, OUT ) do { \ 132 6093 : long res = FUNC( (OUT), (void const *)wire_laddr, wire_sz ); \ 133 6093 : if( FD_UNLIKELY( res<0L ) ) return res; \ 134 6093 : wire_laddr += (ulong)res; \ 135 6093 : wire_sz -= (ulong)res; \ 136 6093 : } while(0) 137 : 138 24378 : #define FD_TLS_ENCODE_SUB( FUNC, IN ) (__extension__({ \ 139 24378 : long res = FUNC( (IN), (void *)wire_laddr, wire_sz ); \ 140 24378 : if( FD_UNLIKELY( res<0L ) ) return res; \ 141 24378 : wire_laddr += (ulong)res; \ 142 24378 : wire_sz -= (ulong)res; \ 143 24378 : (ulong)res; \ 144 24378 : })) 145 : 146 : #endif /* HEADER_fd_src_waltz_tls_fd_tls_serde_h */