Skip to content

Commit a2bd936

Browse files
committed
MDEV-33161 Function pointer signature mismatch in LF_HASH
In cmake -DWITH_UBSAN=ON builds with clang but not with GCC, -fsanitize=undefined will flag several runtime errors on function pointer mismatch related to the lock-free hash table LF_HASH. Let us use matching function signatures and remove function pointer casts in order to avoid potential bugs due to undefined behaviour. These errors could be caught at compilation time by -Wcast-function-type-strict, which is available starting with clang-16, but not available in any version of GCC as of now. The old GCC flag -Wcast-function-type is enabled as part of -Wextra, but it specifically does not catch these errors. Reviewed by: Vladislav Vaintroub
1 parent 246c0b3 commit a2bd936

File tree

12 files changed

+137
-131
lines changed

12 files changed

+137
-131
lines changed

mysys/lf_alloc-pin.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,10 @@ void lf_pinbox_put_pins(LF_PINS *pins)
242242
return;
243243
}
244244

245-
static int ptr_cmp(void **a, void **b)
245+
static int ptr_cmp(const void *pa, const void *pb)
246246
{
247+
const void *const*a= pa;
248+
const void *const*b= pb;
247249
return *a < *b ? -1 : *a == *b ? 0 : 1;
248250
}
249251

@@ -283,8 +285,10 @@ struct st_harvester {
283285
callback forlf_dynarray_iterate:
284286
scan all pins of all threads and accumulate all pins
285287
*/
286-
static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
288+
static int harvest_pins(void *e, void *h)
287289
{
290+
LF_PINS *el= e;
291+
struct st_harvester *hv= h;
288292
int i;
289293
LF_PINS *el_end= el+MY_MIN(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
290294
for (; el < el_end; el++)
@@ -310,8 +314,9 @@ static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
310314
callback forlf_dynarray_iterate:
311315
scan all pins of all threads and see if addr is present there
312316
*/
313-
static int match_pins(LF_PINS *el, void *addr)
317+
static int match_pins(void *e, void *addr)
314318
{
319+
LF_PINS *el= e;
315320
int i;
316321
LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
317322
for (; el < el_end; el++)
@@ -352,13 +357,12 @@ static void lf_pinbox_real_free(LF_PINS *pins)
352357
hv.granary= addr;
353358
hv.npins= npins;
354359
/* scan the dynarray and accumulate all pinned addresses */
355-
lf_dynarray_iterate(&pinbox->pinarray,
356-
(lf_dynarray_func)harvest_pins, &hv);
360+
lf_dynarray_iterate(&pinbox->pinarray, harvest_pins, &hv);
357361

358362
npins= (int)(hv.granary-addr);
359363
/* and sort them */
360364
if (npins)
361-
qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
365+
qsort(addr, npins, sizeof(void *), ptr_cmp);
362366
}
363367
}
364368
#endif
@@ -387,8 +391,7 @@ static void lf_pinbox_real_free(LF_PINS *pins)
387391
}
388392
else /* no alloca - no cookie. linear search here */
389393
{
390-
if (lf_dynarray_iterate(&pinbox->pinarray,
391-
(lf_dynarray_func)match_pins, cur))
394+
if (lf_dynarray_iterate(&pinbox->pinarray, match_pins, cur))
392395
goto found;
393396
}
394397
}
@@ -416,10 +419,11 @@ static void lf_pinbox_real_free(LF_PINS *pins)
416419
'first' and 'last' are the ends of the linked list of nodes:
417420
first->el->el->....->el->last. Use first==last to free only one element.
418421
*/
419-
static void alloc_free(uchar *first,
420-
uchar volatile *last,
421-
LF_ALLOCATOR *allocator)
422+
static void alloc_free(void *f, void *l, void *alloc)
422423
{
424+
uchar *first= f;
425+
uchar volatile *last= l;
426+
LF_ALLOCATOR *allocator= alloc;
423427
/*
424428
we need a union here to access type-punned pointer reliably.
425429
otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
@@ -448,8 +452,7 @@ static void alloc_free(uchar *first,
448452
*/
449453
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
450454
{
451-
lf_pinbox_init(&allocator->pinbox, free_ptr_offset,
452-
(lf_pinbox_free_func *)alloc_free, allocator);
455+
lf_pinbox_init(&allocator->pinbox, free_ptr_offset, alloc_free, allocator);
453456
allocator->top= 0;
454457
allocator->mallocs= 0;
455458
allocator->element_size= size;

mysys/thr_mutex.c

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,10 @@ my_bool safe_mutex_deadlock_detector= 1; /* On by default */
6262
static struct st_safe_mutex_create_info_t *safe_mutex_create_root= NULL;
6363
#endif
6464

65-
static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
66-
safe_mutex_deadlock_t *locked_mutex);
67-
static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
68-
safe_mutex_t *current_mutex);
69-
static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
70-
safe_mutex_t *delete_mutex);
71-
static my_bool remove_from_used_mutex(safe_mutex_deadlock_t *locked_mutex,
72-
safe_mutex_t *mutex);
65+
static my_bool add_used_to_locked_mutex(void *used, void *locked);
66+
static my_bool add_to_locked_mutex(void *locked, void *current);
67+
static my_bool remove_from_locked_mutex(void *m, void* remove);
68+
static my_bool remove_from_used_mutex(void *locked, void *m);
7369
static void print_deadlock_warning(safe_mutex_t *new_mutex,
7470
safe_mutex_t *conflicting_mutex);
7571
#endif
@@ -373,8 +369,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
373369
are now locking (C) in B->C, then we would add C into
374370
B->locked_mutex and A->locked_mutex
375371
*/
376-
my_hash_iterate(mutex_root->used_mutex,
377-
(my_hash_walk_action) add_used_to_locked_mutex,
372+
my_hash_iterate(mutex_root->used_mutex, add_used_to_locked_mutex,
378373
deadlock);
379374

380375
/*
@@ -654,12 +649,8 @@ void safe_mutex_free_deadlock_data(safe_mutex_t *mp)
654649
if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION) && mp->used_mutex != NULL)
655650
{
656651
pthread_mutex_lock(&THR_LOCK_mutex);
657-
my_hash_iterate(mp->used_mutex,
658-
(my_hash_walk_action) remove_from_locked_mutex,
659-
mp);
660-
my_hash_iterate(mp->locked_mutex,
661-
(my_hash_walk_action) remove_from_used_mutex,
662-
mp);
652+
my_hash_iterate(mp->used_mutex, remove_from_locked_mutex, mp);
653+
my_hash_iterate(mp->locked_mutex, remove_from_used_mutex, mp);
663654
pthread_mutex_unlock(&THR_LOCK_mutex);
664655

665656
my_hash_free(mp->used_mutex);
@@ -709,15 +700,15 @@ void safe_mutex_end(FILE *file __attribute__((unused)))
709700
#endif /* SAFE_MUTEX_DETECT_DESTROY */
710701
}
711702

712-
static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
713-
safe_mutex_deadlock_t *locked_mutex)
703+
static my_bool add_used_to_locked_mutex(void *used, void *locked)
714704
{
705+
safe_mutex_t *used_mutex= used;
706+
safe_mutex_deadlock_t *locked_mutex= locked;
715707
/* Add mutex to all parent of the current mutex */
716708
if (!locked_mutex->warning_only)
717709
{
718710
(void) my_hash_iterate(locked_mutex->mutex->locked_mutex,
719-
(my_hash_walk_action) add_to_locked_mutex,
720-
used_mutex);
711+
add_to_locked_mutex, used_mutex);
721712
/* mark that locked_mutex is locked after used_mutex */
722713
(void) add_to_locked_mutex(locked_mutex, used_mutex);
723714
}
@@ -729,12 +720,13 @@ static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
729720
register that locked_mutex was locked after current_mutex
730721
*/
731722

732-
static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
733-
safe_mutex_t *current_mutex)
723+
static my_bool add_to_locked_mutex(void *locked, void *current)
734724
{
725+
safe_mutex_deadlock_t *locked_mutex= locked;
726+
safe_mutex_t *current_mutex= current;
735727
DBUG_ENTER("add_to_locked_mutex");
736-
DBUG_PRINT("info", ("inserting 0x%lx into 0x%lx (id: %lu -> %lu)",
737-
(ulong) locked_mutex, (long) current_mutex,
728+
DBUG_PRINT("info", ("inserting %p into %p (id: %lu -> %lu)",
729+
locked_mutex, current_mutex,
738730
locked_mutex->id, current_mutex->id));
739731
if (my_hash_insert(current_mutex->locked_mutex, (uchar*) locked_mutex))
740732
{
@@ -762,13 +754,14 @@ static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
762754
When counter goes to 0, we delete the safe_mutex_deadlock_t entry.
763755
*/
764756

765-
static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
766-
safe_mutex_t *delete_mutex)
757+
static my_bool remove_from_locked_mutex(void *m, void *remove)
767758
{
759+
safe_mutex_t *mp= m;
760+
safe_mutex_t *delete_mutex= remove;
768761
safe_mutex_deadlock_t *found;
769762
DBUG_ENTER("remove_from_locked_mutex");
770-
DBUG_PRINT("enter", ("delete_mutex: 0x%lx mutex: 0x%lx (id: %lu <- %lu)",
771-
(ulong) delete_mutex, (ulong) mp,
763+
DBUG_PRINT("enter", ("delete_mutex: %p mutex: %p (id: %lu <- %lu)",
764+
delete_mutex, mp,
772765
delete_mutex->id, mp->id));
773766

774767
found= (safe_mutex_deadlock_t *) my_hash_search(mp->locked_mutex,
@@ -786,12 +779,13 @@ static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
786779
DBUG_RETURN(0);
787780
}
788781

789-
static my_bool remove_from_used_mutex(safe_mutex_deadlock_t *locked_mutex,
790-
safe_mutex_t *mutex)
782+
static my_bool remove_from_used_mutex(void *locked, void *m)
791783
{
784+
safe_mutex_deadlock_t *locked_mutex= locked;
785+
safe_mutex_t *mutex= m;
792786
DBUG_ENTER("remove_from_used_mutex");
793-
DBUG_PRINT("enter", ("delete_mutex: 0x%lx mutex: 0x%lx (id: %lu <- %lu)",
794-
(ulong) mutex, (ulong) locked_mutex,
787+
DBUG_PRINT("enter", ("delete_mutex: %p mutex: %p (id: %lu <- %lu)",
788+
mutex, locked_mutex,
795789
mutex->id, locked_mutex->id));
796790
if (my_hash_delete(locked_mutex->mutex->used_mutex, (uchar*) mutex))
797791
{

mysys/waiting_threads.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,10 @@ static void wt_resource_destroy(uchar *arg)
424424
It's called from lf_hash when an element is inserted.
425425
*/
426426
static void wt_resource_init(LF_HASH *hash __attribute__((unused)),
427-
WT_RESOURCE *rc, WT_RESOURCE_ID *id)
427+
void *resource, const void *ident)
428428
{
429+
WT_RESOURCE *rc= resource;
430+
const WT_RESOURCE_ID *id= ident;
429431
DBUG_ENTER("wt_resource_init");
430432
rc->id= *id;
431433
rc->waiter_count= 0;

sql/mdl.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,10 @@ struct mdl_iterate_arg
762762
};
763763

764764

765-
static my_bool mdl_iterate_lock(MDL_lock *lock, mdl_iterate_arg *arg)
765+
static my_bool mdl_iterate_lock(void *lk, void *a)
766766
{
767+
MDL_lock *lock= static_cast<MDL_lock*>(lk);
768+
mdl_iterate_arg *arg= static_cast<mdl_iterate_arg*>(a);
767769
/*
768770
We can skip check for m_strategy here, becase m_granted
769771
must be empty for such locks anyway.
@@ -786,14 +788,13 @@ int mdl_iterate(mdl_iterator_callback callback, void *arg)
786788
{
787789
DBUG_ENTER("mdl_iterate");
788790
mdl_iterate_arg argument= { callback, arg };
789-
LF_PINS *pins= mdl_locks.get_pins();
790791
int res= 1;
791792

792-
if (pins)
793+
if (LF_PINS *pins= mdl_locks.get_pins())
793794
{
794795
res= mdl_iterate_lock(mdl_locks.m_backup_lock, &argument) ||
795-
lf_hash_iterate(&mdl_locks.m_locks, pins,
796-
(my_hash_walk_action) mdl_iterate_lock, &argument);
796+
lf_hash_iterate(&mdl_locks.m_locks, pins, mdl_iterate_lock,
797+
&argument);
797798
lf_hash_put_pins(pins);
798799
}
799800
DBUG_RETURN(res);

sql/sql_base.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,10 @@ class list_open_tables_arg
252252
};
253253

254254

255-
static my_bool list_open_tables_callback(TDC_element *element,
256-
list_open_tables_arg *arg)
255+
static my_bool list_open_tables_callback(void *el, void *a)
257256
{
257+
TDC_element *element= static_cast<TDC_element*>(el);
258+
list_open_tables_arg *arg= static_cast<list_open_tables_arg*>(a);
258259
const Lex_ident_db
259260
db= Lex_ident_db(Lex_cstring_strlen((const char*) element->m_key));
260261
const char *table_name= db.str + db.length + 1;
@@ -302,8 +303,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd,
302303
DBUG_ENTER("list_open_tables");
303304
list_open_tables_arg argument(thd, db, wild);
304305

305-
if (tdc_iterate(thd, (my_hash_walk_action) list_open_tables_callback,
306-
&argument, true))
306+
if (tdc_iterate(thd, list_open_tables_callback, &argument, true))
307307
DBUG_RETURN(0);
308308

309309
DBUG_RETURN(argument.open_list);
@@ -462,9 +462,10 @@ struct tc_collect_arg
462462
flush_tables_type flush_type;
463463
};
464464

465-
static my_bool tc_collect_used_shares(TDC_element *element,
466-
tc_collect_arg *arg)
465+
static my_bool tc_collect_used_shares(void *el, void *a)
467466
{
467+
TDC_element *element= static_cast<TDC_element*>(el);
468+
tc_collect_arg *arg= static_cast<tc_collect_arg*>(a);
468469
my_bool result= FALSE;
469470

470471
DYNAMIC_ARRAY *shares= &arg->shares;
@@ -573,8 +574,7 @@ bool flush_tables(THD *thd, flush_tables_type flag)
573574
my_init_dynamic_array(PSI_INSTRUMENT_ME, &collect_arg.shares,
574575
sizeof(TABLE_SHARE*), 100, 100, MYF(0));
575576
collect_arg.flush_type= flag;
576-
if (tdc_iterate(thd, (my_hash_walk_action) tc_collect_used_shares,
577-
&collect_arg, true))
577+
if (tdc_iterate(thd, tc_collect_used_shares, &collect_arg, true))
578578
{
579579
/* Release already collected shares */
580580
for (uint i= 0 ; i < collect_arg.shares.elements ; i++)

sql/sql_servers.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,10 @@ struct close_cached_connection_tables_arg
133133
};
134134

135135

136-
static my_bool close_cached_connection_tables_callback(
137-
TDC_element *element, close_cached_connection_tables_arg *arg)
136+
static my_bool close_cached_connection_tables_callback(void *el, void *a)
138137
{
138+
TDC_element *element= static_cast<TDC_element*>(el);
139+
auto arg= static_cast<close_cached_connection_tables_arg*>(a);
139140
TABLE_LIST *tmp;
140141

141142
mysql_mutex_lock(&element->LOCK_table_share);
@@ -188,9 +189,7 @@ static bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
188189
close_cached_connection_tables_arg argument= { thd, connection, 0 };
189190
DBUG_ENTER("close_cached_connections");
190191

191-
if (tdc_iterate(thd,
192-
(my_hash_walk_action) close_cached_connection_tables_callback,
193-
&argument))
192+
if (tdc_iterate(thd, close_cached_connection_tables_callback, &argument))
194193
DBUG_RETURN(true);
195194

196195
DBUG_RETURN(argument.tables ?

sql/sql_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ static void print_cached_tables(void)
116116
/* purecov: begin tested */
117117
puts("DB Table Version Thread Open Lock");
118118

119-
tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true);
119+
tdc_iterate(0, print_cached_tables_callback, NULL, true);
120120

121121
fflush(stdout);
122122
/* purecov: end */

sql/table_cache.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ void tc_purge()
309309
{
310310
Share_free_tables::List purge_tables;
311311

312-
tdc_iterate(0, (my_hash_walk_action) tc_purge_callback, &purge_tables);
312+
tdc_iterate(0, tc_purge_callback, &purge_tables);
313313
while (auto table= purge_tables.pop_front())
314314
intern_close_table(table);
315315
}
@@ -1126,17 +1126,18 @@ struct eliminate_duplicates_arg
11261126

11271127

11281128
static uchar *eliminate_duplicates_get_key(const uchar *element, size_t *length,
1129-
my_bool not_used __attribute__((unused)))
1129+
my_bool)
11301130
{
11311131
LEX_STRING *key= (LEX_STRING *) element;
11321132
*length= key->length;
11331133
return (uchar *) key->str;
11341134
}
11351135

11361136

1137-
static my_bool eliminate_duplicates(TDC_element *element,
1138-
eliminate_duplicates_arg *arg)
1137+
static my_bool eliminate_duplicates(void *el, void *a)
11391138
{
1139+
TDC_element *element= static_cast<TDC_element*>(el);
1140+
eliminate_duplicates_arg *arg= static_cast<eliminate_duplicates_arg*>(a);
11401141
LEX_STRING *key= (LEX_STRING *) alloc_root(&arg->root, sizeof(LEX_STRING));
11411142

11421143
if (!key || !(key->str= (char*) memdup_root(&arg->root, element->m_key,
@@ -1182,7 +1183,7 @@ int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument,
11821183
hash_flags);
11831184
no_dups_argument.action= action;
11841185
no_dups_argument.argument= argument;
1185-
action= (my_hash_walk_action) eliminate_duplicates;
1186+
action= eliminate_duplicates;
11861187
argument= &no_dups_argument;
11871188
}
11881189

0 commit comments

Comments
 (0)