Bug #120070 mysql_options(..., MYSQL_READ_DEFAULT_FILE, ...) randomly fails in multi‑threaded programs when using Connector/C 6.1.2
Submitted: 16 Mar 6:33 Modified: 16 Mar 6:47
Reporter: yueming shu Email Updates:
Status: Open Impact on me:
None 
Category:Connector / C Severity:S7 (Test Cases)
Version:6.1.2 (actual affected versions: 6.1.0 – OS:Linux (Linux (distribution independent, glibc 2.17 or later))
Assigned to: CPU Architecture:x86 (thread-safety, options-file, regression, charset)
Tags: connector/c, is_login_file, multi-thread, mysql_options, MYSQL_READ_DEFAULT_FILE, option-file, thread-safety

[16 Mar 6:33] yueming shu
Description:
When using MySQL Connector/C 6.1.2 (mysql_get_client_version() returns 60102) in a multi‑threaded program, calling mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/absolute/path/to/mysql.cnf") to specify an option file sometimes works and sometimes is completely ignored – the behavior is non‑deterministic. With version 5.5.68 (50568) the same code always applies the option file correctly.

Observed behavior
Option file mysql.cnf content:
[client]
default-character-set=utf8
init-command="set names utf8"

Expected result: After connection, character_set_client and collation_connection should be utf8.

Actual result: Randomly, these variables remain at the default latin1 (e.g., query SHOW VARIABLES LIKE 'character_set_client' returns latin1).

mysql_options() always returns 0 (success), even when the option file is ignored.

Root cause analysis
The problem occurs only in multi‑threaded environments; a simple single‑threaded test does not reproduce it. Historical information indicates that Connector/C 6.1.0 introduced login‑file support (.mylogin.cnf) and used a global variable is_login_file to track whether a login file is being used. In versions 6.1.0 through 6.1.11, this variable is global, so concurrent threads interfere with each other: one thread modifying is_login_file can cause another thread’s option‑file parsing to be skipped, thus ignoring the ordinary option file set by MYSQL_READ_DEFAULT_FILE.
Version 5.5.68 does not have the login‑file feature and therefore lacks this global variable, making its behavior stable.

How to repeat:
Write a multi‑threaded C/C++ program, for example:
\\\\\\\\\\\\\\\\\\\\
#include <mysql.h>
#include <pthread.h>
#include <stdio.h>

#define NUM_THREADS 10
#define HOST "localhost"
#define USER "root"
#define PASS "password"
#define DB "test"

void *thread_func(void *arg) {
    MYSQL *mysql = mysql_init(NULL);
    mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/absolute/path/to/mysql.cnf");
    if (!mysql_real_connect(mysql, HOST, USER, PASS, DB, 0, NULL, 0)) {
        printf("Connect failed\n");
    } else {
        // Check character set
        mysql_query(mysql, "SHOW VARIABLES LIKE 'character_set_client'");
        MYSQL_RES *res = mysql_store_result(mysql);
        MYSQL_ROW row = mysql_fetch_row(res);
        printf("Thread %ld: character_set_client = %s\n", pthread_self(), row[1]);
        mysql_free_result(res);
        mysql_close(mysql);
    }
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_create(&threads[i], NULL, thread_func, NULL);
    }
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }
    return 0;
}
\\\\\\\\\\\\\\\\\\\\

Compile and run the program repeatedly with Connector/C 6.1.2. Observe that some threads output latin1 (failure) and some output utf8 (success).

Run the same program with Connector/C 5.5.68 – all threads output utf8.

Suggested fix:
Change the is_login_file variable, used to indicate whether a login file is active, from a global variable to thread‑local storage to avoid race conditions in multi‑threaded environments. This fix has already been implemented in later releases (e.g., Connector/C 8.0 series). It is recommended to backport the fix to the 6.1 series, or to clearly document that users should upgrade to an unaffected version.
[16 Mar 6:47] yueming shu
Updated Suggested fix:

Change the variable `is_login_file`, which is used to indicate whether a login file is active, from a global variable to thread-local storage to avoid race conditions in multi-threaded environments. 

It is recommended to apply this modification to the Connector/C 6.1 series, or to clearly document that in multi-threaded programs using this version, this issue may occur, and users should upgrade to a version that is not affected.