diff --git a/xwords4/android/jni/utilwrapper.c b/xwords4/android/jni/utilwrapper.c index c8aece2eb..e5ded2a1c 100644 --- a/xwords4/android/jni/utilwrapper.c +++ b/xwords4/android/jni/utilwrapper.c @@ -27,6 +27,7 @@ #include "andutils.h" #include "paths.h" #include "LocalizedStrIncludes.h" +#include "dbgutil.h" #define MAX_QUANTITY_STRS 4 @@ -909,6 +910,7 @@ makeUtil( MPFORMAL EnvThreadInfo* ti, jobject jutil, CurGameInfo* gi, SET_PROC(getDevUtilCtxt); #undef SET_PROC + assertTableFull( vtable, sizeof(*vtable), "util" ); return (XW_UtilCtxt*)util; } /* makeUtil */ @@ -965,6 +967,9 @@ makeDUtil( MPFORMAL EnvThreadInfo* ti, jobject jdutil, VTableMgr* vtMgr, SET_DPROC(notifyPause); SET_DPROC(onDupTimerChanged); +#undef SET_DPROC + + assertTableFull( vtable, sizeof(*vtable), "dutil" ); return &dutil->dutil; } diff --git a/xwords4/common/dbgutil.c b/xwords4/common/dbgutil.c index 6aca6f1c3..f561d92ab 100644 --- a/xwords4/common/dbgutil.c +++ b/xwords4/common/dbgutil.c @@ -126,5 +126,24 @@ devIDTypeToStr(DevIDType typ) } #undef CASESTR +typedef void (*ProcPtr)(); +void +assertTableFull( void* table, size_t sizeInBytes, const XP_UCHAR* tableName ) +{ + if ( 0 != sizeInBytes % sizeof(ProcPtr) ) { + XP_LOGFF( "bad call? vtable size: %zu; proc ptr size: %zu", sizeInBytes, sizeof(ProcPtr) ); + XP_ASSERT( 0 ); + } -#endif + ProcPtr* proc = (ProcPtr*)table; + int count = sizeInBytes / sizeof(ProcPtr); + for ( int ii = 0; ii < count; ++ii ) { + if ( !*proc ) { + XP_LOGFF( "%s.vtable[%d] missing", tableName, ii ); + XP_ASSERT( 0 ); + } + ++proc; + } +} + +#endif /* DEBUG */ diff --git a/xwords4/common/dbgutil.h b/xwords4/common/dbgutil.h index a5ca87dcf..692de8758 100644 --- a/xwords4/common/dbgutil.h +++ b/xwords4/common/dbgutil.h @@ -53,4 +53,10 @@ const char* devIDTypeToStr(DevIDType typ); # define SET_DIRTY( ptr ) # endif +# ifdef DEBUG +void assertTableFull( void* table, size_t sizeInBytes, const XP_UCHAR* tableName ); +# else +# define assertTableFull( table, sizeInBytes, tableName ) +# endif + #endif diff --git a/xwords4/linux/cursesboard.c b/xwords4/linux/cursesboard.c index 66784412a..3e06bda4f 100644 --- a/xwords4/linux/cursesboard.c +++ b/xwords4/linux/cursesboard.c @@ -34,6 +34,7 @@ #include "gsrcwrap.h" #include "linuxsms.h" #include "strutils.h" +#include "dbgutil.h" typedef struct CursesBoardState { CursesAppGlobals* aGlobals; @@ -1128,7 +1129,7 @@ setupCursesUtilCallbacks( CursesBoardGlobals* bGlobals, XW_UtilCtxt* util ) #endif #undef SET_PROC - assertUtilCallbacksSet( util ); + assertTableFull( util->vtable, sizeof(*util->vtable), "curses util" ); } /* setupCursesUtilCallbacks */ static bool diff --git a/xwords4/linux/gtkboard.c b/xwords4/linux/gtkboard.c index 68af06791..d7c6677df 100644 --- a/xwords4/linux/gtkboard.c +++ b/xwords4/linux/gtkboard.c @@ -2232,7 +2232,7 @@ setupGtkUtilCallbacks( GtkGameGlobals* globals, XW_UtilCtxt* util ) #undef SET_PROC - assertUtilCallbacksSet( util ); + assertTableFull( util->vtable, sizeof(*util->vtable), "gtk util" ); } /* setupGtkUtilCallbacks */ #ifndef XWFEATURE_STANDALONE_ONLY diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index b954f0cc1..aaf34f9f5 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -2388,20 +2388,6 @@ setupLinuxUtilCallbacks( XW_UtilCtxt* util ) #undef SET_PROC } -void -assertUtilCallbacksSet( XW_UtilCtxt* util ) -{ - XWStreamCtxt* (**proc)(XW_UtilCtxt*, XP_PlayerAddr ) = - &util->vtable->m_util_makeStreamFromAddr; - for ( int ii = 0; ii < sizeof(*util->vtable)/sizeof(*proc); ++ii ) { - if ( !*proc ) { - XP_LOGF( "%s(): null ptr at index %d", __func__, ii ); - XP_ASSERT( 0 ); - } - ++proc; - } -} - void assertDrawCallbacksSet( const DrawCtxVTable* vtable ) {