Skip to content

Commit

Permalink
handholding for tmpl data structures
Browse files Browse the repository at this point in the history
Add debug time assertions to be used as an early bug oracle during fuzzing and other testing
* Only based on local information, so handholding can be used without any changes
* Focus on data structures currently in use
Drive-by: typo fixes, make magic unique, mark unreachable code with unreachable builtin
  • Loading branch information
two-heart committed Jan 23, 2025
1 parent cc7fa84 commit 604a423
Show file tree
Hide file tree
Showing 29 changed files with 1,262 additions and 124 deletions.
1 change: 1 addition & 0 deletions config/extra/with-handholding.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ CPPFLAGS+=-DFD_GHOST_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_SCRATCH_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_SPAD_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_TOWER_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_TMPL_USE_HANDHOLDING=1
CPPFLAGS+=-DFD_TXN_HANDHOLDING=1
74 changes: 71 additions & 3 deletions src/util/tmpl/fd_deque.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@
// Advanced API for zero-copy usage
my_ele_t * my_deque_peek_head ( my_ele_t * deque ); // peeks at head, returned ptr lifetime is until next op on deque
// caller guarantees that deque is not empty
my_ele_t * my_deque_peek_tail ( my_ele_t * deque ); // peeks at tail, returned ptr lifetime is until next op on deque
// caller guarantees that deque is not empty
my_ele_t * my_deque_peek_index ( my_ele_t * deque, ulong idx ); // peeks at index, returned ptr lifetime is until next op on deque
// caller guarantees that deque is not empty
// idx is wrapped to [0,cnt)
my_ele_t * my_deque_insert_head( my_ele_t * deque ); // inserts uninitialized element at head, returns deque
my_ele_t * my_deque_insert_tail( my_ele_t * deque ); // inserts uninitialized element at tail, returns deque
my_ele_t * my_deque_remove_head( my_ele_t * deque ); // removes head, returns deque
Expand Down Expand Up @@ -107,6 +111,7 @@
remove operation (remove_all is fine on an empty deque). */

#include "../bits/fd_bits.h"
#include "../log/fd_log.h"

#include <stddef.h>

Expand All @@ -131,6 +136,13 @@
#error "DEQUE_MAX must be positive"
#endif

/* FD_TMPL_USE_HANDHOLDING is disabled by default in production */

#ifndef FD_TMPL_USE_HANDHOLDING
#define FD_UNDEF_HANDHOLDING
#define FD_TMPL_USE_HANDHOLDING 0
#endif

/* Implementation *****************************************************/

#define DEQUE_(x) FD_EXPAND_THEN_CONCAT3(DEQUE_NAME,_,x)
Expand Down Expand Up @@ -191,6 +203,10 @@ FD_FN_CONST static inline ulong DEQUE_(footprint)( void ) { return sizeof (DEQUE

static inline void *
DEQUE_(new)( void * shmem ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( !shmem ) ) FD_LOG_ERR(( "NULL shmem" ));
if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, DEQUE_(align)() ) ) ) FD_LOG_ERR(( "unaligned shmem" ));
#endif
DEQUE_(private_t) * hdr = (DEQUE_(private_t) *)shmem;
/* These values are large enough that underflow/overflow will never
happen in practical usage. For example, it would take hundreds of
Expand All @@ -211,8 +227,16 @@ DEQUE_(join)( void * shdeque ) {
return hdr->deque;
}

static inline void * DEQUE_(leave) ( DEQUE_T * deque ) { return (void *)DEQUE_(private_hdr_from_deque)( deque ); }
static inline void * DEQUE_(delete)( void * shdeque ) { return shdeque; }
static inline void * DEQUE_(leave) ( DEQUE_T * deque ) { return (void *)DEQUE_(private_hdr_from_deque)( deque ); }

static inline void *
DEQUE_(delete)( void * shdeque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( !shdeque ) ) FD_LOG_ERR(( "NULL shdeque" ));
if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shdeque, DEQUE_(align)() ) ) ) FD_LOG_ERR(( "unaligned shdeque" ));
#endif
return shdeque;
}

FD_FN_CONST static inline ulong DEQUE_(max)( DEQUE_T const * deque ) { (void)deque; return (ulong)(DEQUE_MAX); }

Expand Down Expand Up @@ -243,6 +267,9 @@ DEQUE_(full)( DEQUE_T const * deque ) {
static inline DEQUE_T *
DEQUE_(push_head)( DEQUE_T * deque,
DEQUE_T ele ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->start--;
hdr->deque[ DEQUE_(private_slot)( hdr->start ) ] = ele;
Expand All @@ -252,6 +279,9 @@ DEQUE_(push_head)( DEQUE_T * deque,
static inline DEQUE_T *
DEQUE_(push_tail)( DEQUE_T * deque,
DEQUE_T ele ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->deque[ DEQUE_(private_slot)( hdr->end ) ] = ele;
hdr->end++;
Expand All @@ -260,6 +290,9 @@ DEQUE_(push_tail)( DEQUE_T * deque,

static inline DEQUE_T
DEQUE_(pop_head)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T ele = hdr->deque[ DEQUE_(private_slot)( hdr->start ) ];
hdr->start++;
Expand All @@ -268,6 +301,9 @@ DEQUE_(pop_head)( DEQUE_T * deque ) {

static inline DEQUE_T
DEQUE_(pop_tail)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->end--;
return hdr->deque[ DEQUE_(private_slot)( hdr->end ) ];
Expand Down Expand Up @@ -321,6 +357,10 @@ DEQUE_(push_tail_wrap)( DEQUE_T * deque,

static inline DEQUE_T
DEQUE_(pop_idx_tail)( DEQUE_T * deque, ulong idx ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
if( FD_UNLIKELY( idx>=DEQUE_(cnt)( deque ) ) ) FD_LOG_ERR(( "index out of bounds" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T * cur = &hdr->deque[ DEQUE_(private_slot)( hdr->start + idx ) ];
DEQUE_T ele = *cur;
Expand Down Expand Up @@ -353,6 +393,9 @@ DEQUE_(peek_tail)( DEQUE_T * deque ) {

FD_FN_PURE static inline DEQUE_T *
DEQUE_(peek_index)( DEQUE_T * deque, ulong idx ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( idx>=DEQUE_(cnt)( deque ) ) ) FD_LOG_ERR(( "index out of bounds" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
return hdr->deque + DEQUE_(private_slot)( hdr->start + idx );
}
Expand All @@ -375,6 +418,9 @@ DEQUE_(peek_tail_const)( DEQUE_T const * deque ) {

FD_FN_PURE static inline DEQUE_T const *
DEQUE_(peek_index_const)( DEQUE_T const * deque, ulong idx ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( idx>=DEQUE_(cnt)( deque ) ) ) FD_LOG_ERR(( "index out of bounds" ));
#endif
DEQUE_(private_t) const * hdr = DEQUE_(private_const_hdr_from_deque)( deque );
return hdr->deque + DEQUE_(private_slot)( hdr->start + idx );
}
Expand All @@ -386,13 +432,19 @@ static inline DEQUE_T * DEQUE_(remove_tail)( DEQUE_T * deque ) { DEQUE_(private_

static inline DEQUE_T *
DEQUE_(push_head_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->start--;
return &hdr->deque[ DEQUE_(private_slot)( hdr->start ) ];
}

static inline DEQUE_T *
DEQUE_(push_tail_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(full)( deque ) ) ) FD_LOG_ERR(( "cannot push to full deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T * ele = &hdr->deque[ DEQUE_(private_slot)( hdr->end ) ];
hdr->end++;
Expand All @@ -401,6 +453,9 @@ DEQUE_(push_tail_nocopy)( DEQUE_T * deque ) {

static inline DEQUE_T *
DEQUE_(pop_head_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_T * ele = &hdr->deque[ DEQUE_(private_slot)( hdr->start ) ];
hdr->start++;
Expand All @@ -409,6 +464,9 @@ DEQUE_(pop_head_nocopy)( DEQUE_T * deque ) {

static inline DEQUE_T *
DEQUE_(pop_tail_nocopy)( DEQUE_T * deque ) {
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( DEQUE_(empty)( deque ) ) ) FD_LOG_ERR(( "cannot pop from empty deque" ));
#endif
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
hdr->end--;
return &hdr->deque[ DEQUE_(private_slot)( hdr->end ) ];
Expand Down Expand Up @@ -463,13 +521,19 @@ DEQUE_(iter_prev)( DEQUE_T const * deque, DEQUE_(iter_t) iter ) {

static inline DEQUE_T *
DEQUE_(iter_ele)( DEQUE_T * deque, DEQUE_(iter_t) iter ) {
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
DEQUE_(private_t) * hdr = DEQUE_(private_hdr_from_deque)( deque );
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( (iter<hdr->start) | (iter>hdr->end) ) ) FD_LOG_ERR(( "iter out of bounds" ));
#endif
return &hdr->deque[ DEQUE_(private_slot)( iter ) ];
}

static inline DEQUE_T const *
DEQUE_(iter_ele_const)( DEQUE_T const * deque, DEQUE_(iter_t) iter ) {
DEQUE_(private_t) const * hdr = DEQUE_(private_const_hdr_from_deque)( deque );
#if FD_TMPL_USE_HANDHOLDING
if( FD_UNLIKELY( (iter<hdr->start) | (iter>hdr->end) ) ) FD_LOG_ERR(( "iter out of bounds" ));
#endif
return &hdr->deque[ DEQUE_(private_slot)( iter ) ];
}

Expand All @@ -480,3 +544,7 @@ FD_PROTOTYPES_END
#undef DEQUE_MAX
#undef DEQUE_T
#undef DEQUE_NAME
#ifdef FD_UNDEF_HANDHOLDING
#undef FD_TMPL_USE_HANDHOLDING
#undef FD_UNDEF_HANDHOLDING
#endif
Loading

0 comments on commit 604a423

Please sign in to comment.