Skip to content

Conversation

malderete
Copy link

@malderete malderete commented Feb 19, 2024

Changes

This patch ensures that MySQL calls plugin->deinit with a valid plugin struct as argument no matter the plugin's type.

There is no reasons not to pass the plugin struct for all the extensible plugin's types.

Rationale

Plugins usually implement "deinit" and "deinit" functions.
Those functions are called only once during the plugin lifecycle, "init" when installing a plugin and "deinit" when uninstalling a plugin (or something went wrong during the init phase).

The following code shows how MySQL decides to call deinit

From sql/sql_plugin.cc

  if (plugin_type_deinitialize[plugin->plugin->type]) {
    if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin)) {
      LogErr(ERROR_LEVEL, ER_PLUGIN_FAILED_DEINITIALIZATION, plugin->name.str,
             plugin_type_names[plugin->plugin->type].str);
    }
  } else if (plugin->plugin->deinit) {
    DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
    if (plugin->plugin->deinit(plugin)) {
      DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
                             plugin->name.str));
    }
  }

Code explanation

Before calling plugin->deinit, MySQL verifies if for the given plugin's type there is a special function that handles the deinit phase. This is achieved by searching (using the plugin's type as index) in the array plugin_type_deinitialize in sql/sql_plugin.cc.

Currently, there are 3 special functions: "ha_finalize_handlerton" (MYSQL_STORAGE_PLUGIN), "finalize_schema_table" (MYSQL_INFORMATION_SCHEMA_PLUGIN) and "finalize_audit_plugin" (MYSQL_AUDIT_PLUGIN).

If there is not a special function then MySQL check if the plugin exposes a "deinit" function and executes it passing the "plugin struct" as argument. Otherwise, MySQL calls the "special function" passing the plugin as argument. Then the special function check if the plugin exposes a "deinit" function and then calls it but it always passes nullptr as argument rather than the "plugin struct".

Note: In case of "init" the code is similar but looks for special functions in the array "plugin_type_initialize"

The documentation says:

deinit: A once-only deinitialization function, or NULL if there is no such function.
The server executes this function when it unloads the plugin, which happens for UNINSTALL PLUGIN or,
for plugins listed in the mysql.plugin table, at server shutdown.
The function takes one argument that points to the internal structure used to identify the plugin It returns zero for success and nonzero for failure.

Doc does not explain that MySQL will always pass nullptr instead of the "plugin struct" for those plugin's types. Also it does not mention that it is plugin responsibility to check that pointer, using that pointer trusting it is not nullptr could crash MySQL.

Because of that, plugins of type "MYSQL_STORAGE_PLUGIN", "MYSQL_INFORMATION_SCHEMA_PLUGIN" and "MYSQL_AUDIT_PLUGIN" need to do something similar to the code below:

static int xxx_deinit(MYSQL_PLUGIN p [[maybe_unused]])
static int xxx_deinit(MYSQL_PLUGIN p __attribute__((unused)))

…'s type by passing a reference to then plugin rather than `nullptr`.

Before calling "plugin->deinit", MySQL verifies if for the given plugin's type there is a special function that handles the deinit phase.
This is achieved by verifiying the array "plugin_type_deinitialize" in `sql/sql_plugin.cc`.
Currently, there are 3 special functions: "ha_finalize_handlerton" (MYSQL_STORAGE_PLUGIN),
"finalize_schema_table" (MYSQL_INFORMATION_SCHEMA_PLUGIN) and "finalize_audit_plugin" (MYSQL_AUDIT_PLUGIN).

If there is not a special fuinction then MySQL check if the plugin exposes a "deinit" function and executes it passing the "plugin" as argument.
Otherwise, MySQL calls the "special function" passing the plugin as argument. Then the special function check if the plugin exposes a "deinit"
function and calls it but it always pass `nullptr` as argument rather than the plugin.

Because of that, plugin's deinit cannot use plugin's struct and need to add "maybe_unused" (or "__attribute__((unused))") to the signature.
@mysql-oca-bot
Copy link

Hi, thank you for your contribution. Please confirm this code is submitted under the terms of the OCA (Oracle's Contribution Agreement) you have previously signed by cutting and pasting the following text as a comment:
"I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it."
Thanks

@malderete
Copy link
Author

I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

@mysql-oca-bot
Copy link

Hi, thank you for your contribution. Your code has been assigned to an internal queue. Please follow
bug http://bugs.mysql.com/bug.php?id=114064 for updates.
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants