Tag my_printf_error with ATTRIBUTE_FORMAT

[Breaking]
The `my_print_error` service passes formats and args directly
to `my_vsnprintf`. Just like the `my_snprintf` service,
I increased this service’s major version because:
* Custom suffixes are now a thing
  (and custom specifiers will soon no longer be).
* GCC `-Wformat` now checks formats sent to them.
This commit is contained in:
ParadoxV5 2024-07-31 22:42:56 -06:00 committed by Sergei Golubchik
parent 618afa32ce
commit 2047483417
10 changed files with 31 additions and 22 deletions

View File

@ -31,6 +31,7 @@ extern "C" {
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#include <my_attribute.h>
#define ME_ERROR_LOG 64 /* Write the message to the error log */ #define ME_ERROR_LOG 64 /* Write the message to the error log */
#define ME_ERROR_LOG_ONLY 128 /* Write the error message to error log only */ #define ME_ERROR_LOG_ONLY 128 /* Write the error message to error log only */
@ -40,8 +41,12 @@ extern "C" {
extern struct my_print_error_service_st { extern struct my_print_error_service_st {
void (*my_error_func)(unsigned int nr, unsigned long MyFlags, ...); void (*my_error_func)(unsigned int nr, unsigned long MyFlags, ...);
void (*my_printf_error_func)(unsigned int nr, const char *fmt, unsigned long MyFlags,...); void (*my_printf_error_func)(unsigned int nr, const char *fmt,
void (*my_printv_error_func)(unsigned int error, const char *format, unsigned long MyFlags, va_list ap); unsigned long MyFlags, ...)
ATTRIBUTE_FORMAT_FPTR(printf, 2, 4);
void (*my_printv_error_func)(unsigned int error, const char *format,
unsigned long MyFlags, va_list ap)
ATTRIBUTE_FORMAT_FPTR(printf, 2, 0);
} *my_print_error_service; } *my_print_error_service;
#ifdef MYSQL_DYNAMIC_PLUGIN #ifdef MYSQL_DYNAMIC_PLUGIN
@ -52,8 +57,12 @@ extern struct my_print_error_service_st {
#else #else
extern void my_error(unsigned int nr, unsigned long MyFlags, ...); extern void my_error(unsigned int nr, unsigned long MyFlags, ...);
extern void my_printf_error(unsigned int my_err, const char *format, unsigned long MyFlags, ...); extern void my_printf_error(unsigned int my_err, const char *format,
extern void my_printv_error(unsigned int error, const char *format, unsigned long MyFlags,va_list ap); unsigned long MyFlags, ...)
ATTRIBUTE_FORMAT(printf, 2, 4);
extern void my_printv_error(unsigned int error, const char *format,
unsigned long MyFlags,va_list ap)
ATTRIBUTE_FORMAT(printf, 2, 0);
#endif /* MYSQL_DYNAMIC_PLUGIN */ #endif /* MYSQL_DYNAMIC_PLUGIN */
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -29,7 +29,7 @@
#define VERSION_logger 0x0100 #define VERSION_logger 0x0100
#define VERSION_my_crypt 0x0100 #define VERSION_my_crypt 0x0100
#define VERSION_my_md5 0x0100 #define VERSION_my_md5 0x0100
#define VERSION_my_print_error 0x0100 #define VERSION_my_print_error 0x0200
#define VERSION_my_sha1 0x0101 #define VERSION_my_sha1 0x0101
#define VERSION_my_sha2 0x0100 #define VERSION_my_sha2 0x0100
#define VERSION_my_snprintf 0x0200 #define VERSION_my_snprintf 0x0200

View File

@ -62,7 +62,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
PAM_DEBUG((stderr, "PAM: opening pipes.\n")); PAM_DEBUG((stderr, "PAM: opening pipes.\n"));
if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0) if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0)
{ {
my_printf_error(ENOEXEC, "pam: cannot create pipes (errno: %M)", my_printf_error(ENOEXEC, "pam: cannot create pipes (errno: %iE)",
ME_ERROR_LOG_ONLY, errno); ME_ERROR_LOG_ONLY, errno);
return CR_ERROR; return CR_ERROR;
} }
@ -94,7 +94,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
if (res) if (res)
{ {
my_printf_error(ENOEXEC, "pam: cannot exec %s (errno: %M)", my_printf_error(ENOEXEC, "pam: cannot exec %s (errno: %iE)",
ME_ERROR_LOG_ONLY, toolpath, errno); ME_ERROR_LOG_ONLY, toolpath, errno);
goto error_ret; goto error_ret;
} }

View File

@ -755,7 +755,7 @@ static int user_coll_fill(struct user_coll *c, char *users,
if (cmp_user && take_over_cmp) if (cmp_user && take_over_cmp)
{ {
ADD_ATOMIC(internal_stop_logging, 1); ADD_ATOMIC(internal_stop_logging, 1);
CLIENT_ERROR(1, "User '%.*b' was removed from the" CLIENT_ERROR(1, "User '%.*sB' was removed from the"
" server_audit_excl_users.", " server_audit_excl_users.",
MYF(ME_WARNING), (int) cmp_length, users); MYF(ME_WARNING), (int) cmp_length, users);
ADD_ATOMIC(internal_stop_logging, -1); ADD_ATOMIC(internal_stop_logging, -1);
@ -765,7 +765,7 @@ static int user_coll_fill(struct user_coll *c, char *users,
else if (cmp_user) else if (cmp_user)
{ {
ADD_ATOMIC(internal_stop_logging, 1); ADD_ATOMIC(internal_stop_logging, 1);
CLIENT_ERROR(1, "User '%.*b' is in the server_audit_incl_users, " CLIENT_ERROR(1, "User '%.*sB' is in the server_audit_incl_users, "
"so wasn't added.", MYF(ME_WARNING), (int) cmp_length, users); "so wasn't added.", MYF(ME_WARNING), (int) cmp_length, users);
ADD_ATOMIC(internal_stop_logging, -1); ADD_ATOMIC(internal_stop_logging, -1);
remove_user(users); remove_user(users);

View File

@ -988,14 +988,14 @@ bool Field::check_assignability_from(const Type_handler *from,
*/ */
if (table->s->db.str && table->s->table_name.str) if (table->s->db.str && table->s->table_name.str)
my_printf_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, my_printf_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION,
"Cannot cast '%s' as '%s' in assignment of %`s.%`s.%`s", "Cannot cast '%s' as '%s' in assignment of %sQ.%sQ.%sQ",
MYF(error ? 0 : ME_WARNING), MYF(error ? 0 : ME_WARNING),
from->name().ptr(), type_handler()->name().ptr(), from->name().ptr(), type_handler()->name().ptr(),
table->s->db.str, table->s->table_name.str, table->s->db.str, table->s->table_name.str,
field_name.str); field_name.str);
else else
my_printf_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, my_printf_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION,
"Cannot cast '%s' as '%s' in assignment of %`s", "Cannot cast '%s' as '%s' in assignment of %sQ",
MYF(error ? 0 : ME_WARNING), MYF(error ? 0 : ME_WARNING),
from->name().ptr(), type_handler()->name().ptr(), from->name().ptr(), type_handler()->name().ptr(),
field_name.str); field_name.str);

View File

@ -1033,7 +1033,7 @@ static Item *create_comparator(MY_XPATH *xpath,
else else
my_printf_error(ER_UNKNOWN_ERROR, my_printf_error(ER_UNKNOWN_ERROR,
"XPATH error: " "XPATH error: "
"comparison of two nodesets is not supported: '%.32T'", "comparison of two nodesets is not supported: '%.32sT'",
MYF(0), context->beg); MYF(0), context->beg);
return 0; // TODO: Comparison of two nodesets return 0; // TODO: Comparison of two nodesets
@ -2693,7 +2693,7 @@ my_xpath_parse_VariableReference(MY_XPATH *xpath)
my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'", my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'",
MYF(0), len, dollar_pos); MYF(0), len, dollar_pos);
else else
my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.32T'", my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.32sT'",
MYF(0), dollar_pos); MYF(0), dollar_pos);
} }
} }
@ -2829,7 +2829,7 @@ bool Item_xml_str_func::fix_fields(THD *thd, Item **ref)
my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'", my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'",
MYF(0), clen, xpath.lasttok.beg); MYF(0), clen, xpath.lasttok.beg);
else else
my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.32T'", my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.32sT'",
MYF(0), xpath.lasttok.beg); MYF(0), xpath.lasttok.beg);
return true; return true;

View File

@ -3497,12 +3497,12 @@ end:
target user, so printing `priv_user@priv_host` is not incorrect. target user, so printing `priv_user@priv_host` is not incorrect.
*/ */
if (!host.str) if (!host.str)
my_printf_error(ER_INVALID_ROLE, "User %`s@%`s has not been granted role %`s", my_printf_error(ER_INVALID_ROLE, "User %sQ@%sQ has not been granted role %sQ",
MYF(0), thd->security_ctx->priv_user, MYF(0), thd->security_ctx->priv_user,
thd->security_ctx->priv_host, rolename.str); thd->security_ctx->priv_host, rolename.str);
else else
/* Role is not granted but current user can see the role */ /* Role is not granted but current user can see the role */
my_printf_error(ER_INVALID_ROLE, "User %`s@%`s has not been granted role %`s", my_printf_error(ER_INVALID_ROLE, "User %sQ@%sQ has not been granted role %sQ",
MYF(0), user.str, host.str, rolename.str); MYF(0), user.str, host.str, rolename.str);
} }
else else

View File

@ -339,7 +339,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
if (field_data_type_info_image.append(create_fields)) if (field_data_type_info_image.append(create_fields))
{ {
my_printf_error(ER_CANT_CREATE_TABLE, my_printf_error(ER_CANT_CREATE_TABLE,
"Cannot create table %`s: " "Cannot create table %sQ: "
"Building the field data type info image failed.", "Building the field data type info image failed.",
MYF(0), table.str); MYF(0), table.str);
DBUG_RETURN(frm); DBUG_RETURN(frm);
@ -486,7 +486,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
if (field_data_type_info_image.length() > 0xFFFF) if (field_data_type_info_image.length() > 0xFFFF)
{ {
my_printf_error(ER_CANT_CREATE_TABLE, my_printf_error(ER_CANT_CREATE_TABLE,
"Cannot create table %`s: " "Cannot create table %sQ: "
"field data type info image is too large. " "field data type info image is too large. "
"Decrease the number of columns with " "Decrease the number of columns with "
"extended data types.", "extended data types.",
@ -553,7 +553,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
if (key_info_length > UINT_MAX16) if (key_info_length > UINT_MAX16)
{ {
my_printf_error(ER_CANT_CREATE_TABLE, my_printf_error(ER_CANT_CREATE_TABLE,
"Cannot create table %`s: index information is too long. " "Cannot create table %sQ: index information is too long. "
"Decrease number of indexes or use shorter index names or shorter comments.", "Decrease number of indexes or use shorter index names or shorter comments.",
MYF(0), table.str); MYF(0), table.str);
goto err; goto err;

View File

@ -1036,7 +1036,7 @@ ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze() noexcept
static void dict_table_open_failed(const table_name_t &name) static void dict_table_open_failed(const table_name_t &name)
{ {
my_printf_error(ER_TABLE_CORRUPT, my_printf_error(ER_TABLE_CORRUPT,
"Table %`.*s.%`s is corrupted." "Table %.*sQ.%sQ is corrupted."
" Please drop the table and recreate.", " Please drop the table and recreate.",
MYF(ME_ERROR_LOG), MYF(ME_ERROR_LOG),
int(name.dblen()), name.m_name, name.basename()); int(name.dblen()), name.m_name, name.basename());
@ -1077,7 +1077,7 @@ dict_table_open_on_name(
ulint algo= table->space->get_compression_algo(); ulint algo= table->space->get_compression_algo();
if (algo <= PAGE_ALGORITHM_LAST && !fil_comp_algo_loaded(algo)) if (algo <= PAGE_ALGORITHM_LAST && !fil_comp_algo_loaded(algo))
my_printf_error(ER_PROVIDER_NOT_LOADED, my_printf_error(ER_PROVIDER_NOT_LOADED,
"Table %`.*s.%`s is compressed with %s," "Table %.*sQ.%sQ is compressed with %s,"
" which is not currently loaded. " " which is not currently loaded. "
"Please load the %s provider plugin" "Please load the %s provider plugin"
" to open the table", " to open the table",

View File

@ -140,7 +140,7 @@ void _ma_report_error(int errcode, const LEX_STRING *name, myf flags)
file_name+= length - 64; file_name+= length - 64;
} }
} }
my_printf_error(errcode, "Got error '%M' for '%s'", my_printf_error(errcode, "Got error '%iE' for '%s'",
flags, errcode, file_name); flags, errcode, file_name);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }