Unexpected function call - mysql

I'm using MySQL 5.0.51a and I uncovered a bug which was causing an infinite loop (ending in a stack overflow and seqgfault) when my program was exiting.
I discovered that if I had a function called shutdown(), it would be called by during a call to mysql_close().
I've included a mimimal example C source file and makefile below to show the issue in action.
In the example, shutdown() gets called despite not being called by main().
What is going on here? Is my shutdown() clashing with a shutdown() in libmysqlclient?
If so, is there a reason gcc doesn't know about it?
I'm using gcc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)
mysql_shutdown.c:
#include <stdio.h>
#include <mysql/mysql.h>
#define HOST "<hostname>"
#define USER "<username>"
#define PASSWD "<password>"
#define DB "<dbname>"
MYSQL *connection;
void shutdown(void)
{
printf("shutdown called\n");
}
int main()
{
connection = mysql_init(NULL);
mysql_real_connect(connection, HOST, USER, PASSWD, DB, 0, NULL, 0);
mysql_close(connection);
return 0;
}
makefile:
mysql_shutdown: mysql_shutdown.c
gcc -Wall -Wextra -Werror `mysql_config --cflags` -o $# $^ `mysql_config --libs`
Output:
$ ./mysql_shutdown
shutdown called
Note that this appears to be the opposite behaviour to that shown in GCC function name conflict. In that case the expected function wasn't being called, whereas in my case, a function is being called when it isn't expected.

What's most likely happening is that, because mysql_config --libs is giving you a list of the MySQL library files and the shutdown() function is in a different object file within the library(s), it's not being bought in.
You have to understand the way most linkers work. What they will do is tie together all the object files that you list explicitly and you end up with a partial executable and a list of symbols that have yet to be resolved.
Then the libraries are searched in an effort to resolve those symbols, by locating the object files within those libraries which can resolve the symbols. Normally what may happen is that you'll find mysql_close() in one of the libraries and load up its object file from that library. But that action may introduce more symbols that need resolving, which can in turn lead to more libraries being searched.
As an example, let's say mysql_close() calls shutdown() which is normally provided in one of the MySQL libraries. However, because you've already defined it, the loading of mysql_close() does not result in having an unresolved shutdown symbol. So there's no need to go looking for it in any of the libraries.
It does result in mysql_close() calling a totally different shutdown(), the one you provided in your code.

Related

C code using gcc cannot link to mysql header?

I'd like to build on this post, because my symptoms are identical, but the solution seems to be something else.
I am working in a Ubuntu container (Ubuntu 16.04.3 LTS), trying to compile a toy C program that will eventually connect to an SQL server. First things first: I have the latest libmysqlclient-dev installed:
root#1234:/home# apt install libmysqlclient-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
libmysqlclient-dev is already the newest version (5.7.24-0ubuntu0.16.04.1).
0 upgraded, 0 newly installed, 0 to remove and 88 not upgraded.
root#1234:/home#
And when I look in the /usr/include/mysql directory, I see the critical header file I'll need:
root#1234:/home# ls -l /usr/include/mysql | grep mysql.h
-rw-r--r-- 1 root root 29207 Oct 4 05:48 /usr/include/mysql/mysql.h
root#1234:/home#
So far, so good. Now I found this little toy program from here:
#include <stdio.h>
#include "/usr/include/mysql/mysql.h"
int main() {
MYSQL mysql;
if(mysql_init(&mysql)==NULL) {
printf("\nInitialization error\n");
return 0;
}
mysql_real_connect(&mysql,"localhost","user","pass","dbname",0,NULL,0);
printf("Client version: %s",mysql_get_client_info());
printf("\nServer version: %s",mysql_get_server_info(&mysql));
mysql_close(&mysql);
return 1;
}
Now, following the advice of the previous post, I compile using the "-I" option to point to the mysql.h header file. (Yes, I am required to use GCC here):
root#1234:/home# gcc -I/usr/include/mysql sqlToy.c
/tmp/cc8c5JmT.o: In function `main':
sqlToy.c:(.text+0x25): undefined reference to `mysql_init'
sqlToy.c:(.text+0x69): undefined reference to `mysql_real_connect'
sqlToy.c:(.text+0x72): undefined reference to `mysql_get_client_info'
sqlToy.c:(.text+0x93): undefined reference to `mysql_get_server_info'
sqlToy.c:(.text+0xb4): undefined reference to `mysql_close'
collect2: error: ld returned 1 exit status
root#1234:/home#
Belly flop! The compiler has no idea what all the mySQL functions are, even though I've done all I can think of to point to that header file. As a sanity check, I made sure those mySQL functions are indeed in that header file; here's one as an example:
root#1234:/home# more /usr/include/mysql/mysql.h | grep mysql_init
libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so
MYSQL * STDCALL mysql_init(MYSQL *mysql);
root#1234:/home#
So while I've pointed the compiler to the mysql.h header file in both my code AND with the "-I" option, it still has no clue what those 'mysql' functions are. The "-I" option was the solution in the previous post, but is not working for me here.
So... What might be the problem? I'm assuming this isn't a compiling problem, but maybe a linking one? In other words, I'm showing GCC where the mysql.h file is, but he is still not using it when processing the code?
Headers are not libraries. You are including the MySQL header during compilation, so these functions are defined, but you are not linking against the library which actually provides those functions.
These functions are provided by the libmysqlclient library, so you need to add the -lmysqlclient flag to your command line to fix this. (Note that this is a lower-case l, not an I.)
Additionally, since you are adding /usr/include/mysql to your system header path, you can include the library as
#include <mysql.h>
You do not need to -- and should not! -- specify the full path to the library in the #include directive.

mySQL and C trouble [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
I'm trying to get started with using mySQL C API for a project that I'm hoping to complete.
I've downloaded the mySQL Community Server version and the mySQL Connector/C from the official site.
Q1: Do I also need to download Connector/ODBC? What is the difference?
So, this is a basic program that I learnt and am trying to compile and link:
#include<stdio.h>
#include<mysql.h>
int main(int argc, char **argv)
{
printf("MySQL client version: %s\n", mysql_get_client_info());
exit(0);
}
I'm extremely confused as to what commands for compilation and linking I should use. When I do the following, this happens:
gcc mySQL.c -I/usr/local/mysql/include
Undefined symbols for architecture x86_64:
"_mysql_get_client_info", referenced from:
_main in mySQL-a3f748.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Can someone just help me out with this? I've struggled a lot and it all seems extremely confusing.
My question is about compiling and linking mySQL C API libraries and not the error.
The header file <mysql.h> only declares the functions and types needed. The actual function definition (its implementation) is in a library you need to link with.
You do that with the -l (lower-case L) option:
gcc mySQL.c -I/usr/local/mysql/include -lmysql
However, since you seem to have installed MySQL in a non-standard location, you might have to use the -L option to specify where the library is located (similar to the -I option):
gcc mySQL.c -I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysql
This should at least make your program build. But there is still another issue that might come up if your MySQL library is not a static library but a dynamic library (i.e. a "DLL"), because the run-time loader will not know the location of the dynamic library. You need a special linker-flag for that too:
gcc mySQL.c -I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysql -Wl,-rpath=usr/local/mysql/lib

bits/string3.h:82: warning: memset used with constant zero length parameter

This is my MCVE using MySQL C API:
#include <my_global.h>
#include <mysql.h>
int main()
{
mysql_init( NULL );
}
Compiling with gcc 4.9.3 -O3 -I /usr/include/mysql produces this warning:
/usr/lib64/mysql/libmysqlclient.a(ssl.cpp.o): In function `memset':
/usr/include/bits/string3.h:82: warning: memset used with constant zero length parameter;
this could be due to transposed parameters
Environment:
Using MySQL 5.7.13 Server and C API 6.1.6 on SLES 12 SP1 VM on XenServer.
My question:
Should I report it as a bug to MySQL or does anybody know how to remove this warning?
Update:
Because a comment mentioned I should play with the arguments in mysql_library_init() I updated the question to a more compact/minimal working example.
Update:
This warning appears while the link process! The compilation works fine.

C MySQL API compiler warning problem with redefinition while including header files

I am compiling a simple c program to test the including of the library files on eclipse cygwin environment mysql-connector-c-6.0.2
The program
#include <my_global.h>
#include <mysql.h>
int main(int argv,char* argc[])
{
printf("my SQL libraries successfully included\n");
return 0;
}
I get the compiler errors as
cygwin warning:
MS-DOS style path detected: C:\MinGW\Workspace\sql_test\Debug
Preferred POSIX equivalent is: /cygdrive/c/MinGW/Workspace/sql_test/Debug
CYGWIN environment variable option "nodosfilewarning" turns off this warning.
Consult the user's guide for more details about POSIX paths:
http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
In file included from ../sql_test.c:8:
D:\mysql-connector-c-6.0.2\include/my_global.h:1416:1: warning: "floatget" redefined
D:\mysql-connector-c-6.0.2\include/my_global.h:1232:1: warning: this is the location of the previous definition
D:\mysql-connector-c-6.0.2\include/my_global.h:1417:1: warning: "floatstore" redefined
D:\mysql-connector-c-6.0.2\include/my_global.h:1231:1: warning: this is the location of the previous definition
D:\mysql-connector-c-6.0.2\include/my_global.h:1418:1: warning: "doubleget" redefined
D:\mysql-connector-c-6.0.2\include/my_global.h:1220:1: warning: this is the location of the previous definition
D:\mysql-connector-c-6.0.2\include/my_global.h:1419:1: warning: "doublestore" redefined
D:\mysql-connector-c-6.0.2\include/my_global.h:1225:1: warning: this is the location of the previous definition
Finished building: ../sql_test.c
I have verified the my_global.h file and the deceleration of these seems to be valid.
How to turn of these redefinition errors?
Where in eclipse and How do i set this "CYGWIN environment variable option "nodosfilewarning" to turn off this warning".
Here you can see the header file my_global.h of
For the warning, define CYGWIN=nodosfilewarning in the OS environment (control panel -> system -> advanced -> environment variables). If that doesn't work, try logging out to make sure nothing is using the old environment.
For the redefine errors, as Bo says, the compiler is telling you exactly where your mistakes are. If you don't understand them, then you should at least post those lines as part of your question.

Problem with MySQL driver for unixODBC on Debian Lenny

On OpenSuse 11.2, I successfully compiled, linked, and ran the following code which installs a data source for a MySQL database with unixODBC:
#include <iostream>
#include <sql.h>
#include <sqlext.h>
#include <odbcinst.h>
/* Add a data source for the following MySQL db: db=testdb, username=test, password = test. */
void inst()
{
BOOL ret = SQLConfigDataSource(NULL, ODBC_ADD_DSN, "MySQL driver",
"DSN=mysource\0UID=test\0PWD=test\0DATABASE=testdb\0\0");
if (!ret) {
DWORD errCode;
char errBuf[SQL_MAX_MESSAGE_LENGTH];
WORD msgLen;
SQLInstallerError(1, &errCode, errBuf, SQL_MAX_MESSAGE_LENGTH, &msgLen);
std::cerr << errBuf << std::endl;
}
}
int main()
{
inst();
return 0;
}
With the same code on Debian Lenny, I have had problems. First, I compiled this code the following way:
c++ -o main main.cc -lodbc -lodbcinst -L/usr/lib/odbc -lmyodbc
It went ok. But when I attempted to run the resulting binary, I got a linker error which in fact was confirmed by typing ldd main:
libmyodbc3_r-3.51.15.so => not found
Although I correctly installed unixODBC and the associated MySQL driver (myodbc) on my host (Debian Lenny) the simplest way (i.e. via aptitude), I could not find this shared library.
I wrongly thought, well, I will create a symlink on /usr/lib/odbc/libmyodbc.so. Anyway now my program returns the following message:
General installer error
So I feel the file libmyodbc3_r-3.51.15.so is really missing.
Note: on Debian Lenny, the version of unixODBC is 2.2.11, and the version of MySQL is 5.0.51a
Anyone ever ran into such a situation ? Any help would be appreciated.
The option
-L/usr/lib/odbc
tells the compiler where to find the library for linking.
But the system doesn't know where to find the library when you run the executable.
You need to either statically link against libmyodbc, or tell the system where to find the library.
The first can be done by changing
-lmyodbc
to
-static -lmyodbc
The second can be done by editing /etc/ld.so.conf (or adding to /etc/ld.so.conf.d) and re-running ldconfig or by setting the LD_LIBRARY_PATH environment variable to include /usr/lib/odbc