From cd5808eb8da13c5626d4bdeb452cef6ada29cb1d Mon Sep 17 00:00:00 2001 From: Ruoyu Zhong Date: Sun, 20 Aug 2023 19:43:57 +0800 Subject: [PATCH] MDEV-31963 Fix libfmt usage in SFORMAT `fmt::detail::make_arg` does not accept temporaries. Make it happy by storing the format arg values in a temporary array first. Signed-off-by: Ruoyu Zhong --- sql/item_strfunc.cc | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 007e2bbc16f6f..4bbf36ec1cf30 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1407,11 +1407,24 @@ namespace fmt { */ String *Item_func_sformat::val_str(String *res) { + /* + A union that stores a numeric format arg value. + fmt::detail::make_arg does not accept temporaries, so all of its numeric + args are temporarily stored in the fmt_args array. + See: https://github.com/fmtlib/fmt/issues/3596 + */ + union Format_arg_store { + longlong val_int; + float val_float; + double val_double; + }; + DBUG_ASSERT(fixed()); - using ctx= fmt::format_context; - String *fmt_arg= NULL; - String *parg= NULL; - fmt::format_args::format_arg *vargs= NULL; + using ctx= fmt::format_context; + String *fmt_arg= NULL; + String *parg= NULL; + fmt::format_args::format_arg *vargs= NULL; + Format_arg_store *fmt_args= NULL; null_value= true; if (!(fmt_arg= args[0]->val_str(res))) @@ -1420,25 +1433,39 @@ String *Item_func_sformat::val_str(String *res) if (!(vargs= new fmt::format_args::format_arg[arg_count - 1])) return NULL; + if (!(fmt_args= new Format_arg_store[arg_count - 1])) + { + delete [] vargs; + return NULL; + } + /* Creates the array of arguments for vformat */ for (uint carg= 1; carg < arg_count; carg++) { switch (args[carg]->result_type()) { case INT_RESULT: - vargs[carg-1]= fmt::detail::make_arg(args[carg]->val_int()); + fmt_args[carg-1].val_int= args[carg]->val_int(); + vargs[carg-1]= fmt::detail::make_arg(fmt_args[carg-1].val_int); break; case DECIMAL_RESULT: // TODO case REAL_RESULT: if (args[carg]->field_type() == MYSQL_TYPE_FLOAT) - vargs[carg-1]= fmt::detail::make_arg((float)args[carg]->val_real()); + { + fmt_args[carg-1].val_float= (float)args[carg]->val_real(); + vargs[carg-1]= fmt::detail::make_arg(fmt_args[carg-1].val_float); + } else - vargs[carg-1]= fmt::detail::make_arg(args[carg]->val_real()); + { + fmt_args[carg-1].val_double= args[carg]->val_real(); + vargs[carg-1]= fmt::detail::make_arg(fmt_args[carg-1].val_double); + } break; case STRING_RESULT: if (!(parg= args[carg]->val_str(&val_arg[carg-1]))) { delete [] vargs; + delete [] fmt_args; return NULL; } vargs[carg-1]= fmt::detail::make_arg(*parg); @@ -1448,6 +1475,7 @@ String *Item_func_sformat::val_str(String *res) default: DBUG_ASSERT(0); delete [] vargs; + delete [] fmt_args; return NULL; } } @@ -1471,6 +1499,7 @@ String *Item_func_sformat::val_str(String *res) null_value= true; } delete [] vargs; + delete [] fmt_args; return null_value ? NULL : res; }