MDEV-21167 LF_PINS::stack_ends_here inaccurate, leading to alloca() larger than stack

Use my_thread_var::stack_ends_here inside lf_pinbox_real_free() for address
where thread stack ends.

Remove LF_PINS::stack_ends_here.
It is not safe to assume that mysys_var that was used during pin allocation,
remains correct during free. E.g with binlog group commit in Innodb,
that frees pins for multiple Innodb transactions, it does not work
correctly.
This commit is contained in:
Vladislav Vaintroub 2019-11-25 22:48:50 +01:00
parent 584ffa02f1
commit ba95c303e3
2 changed files with 5 additions and 10 deletions

View file

@ -65,7 +65,6 @@ typedef struct {
typedef struct {
void * volatile pin[LF_PINBOX_PINS];
LF_PINBOX *pinbox;
void **stack_ends_here;
void *purgatory;
uint32 purgatory_count;
uint32 volatile link;

View file

@ -151,7 +151,6 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox)
*/
LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox)
{
struct st_my_thread_var *var;
uint32 pins, next, top_ver;
LF_PINS *el;
/*
@ -194,12 +193,7 @@ LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox)
el->link= pins;
el->purgatory_count= 0;
el->pinbox= pinbox;
var= my_thread_var;
/*
Threads that do not call my_thread_init() should still be
able to use the LF_HASH.
*/
el->stack_ends_here= (var ? & var->stack_ends_here : NULL);
return el;
}
@ -335,16 +329,18 @@ static void lf_pinbox_real_free(LF_PINS *pins)
void *list;
void **addr= NULL;
void *first= NULL, *last= NULL;
struct st_my_thread_var *var= my_thread_var;
void *stack_ends_here= var ? var->stack_ends_here : NULL;
LF_PINBOX *pinbox= pins->pinbox;
npins= pinbox->pins_in_array+1;
#ifdef HAVE_ALLOCA
if (pins->stack_ends_here != NULL)
if (stack_ends_here != NULL)
{
int alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
/* create a sorted list of pinned addresses, to speed up searches */
if (available_stack_size(&pinbox, *pins->stack_ends_here) >
if (available_stack_size(&pinbox, stack_ends_here) >
alloca_size + ALLOCA_SAFETY_MARGIN)
{
struct st_harvester hv;