stack smashing error - mysql

This is my code:
#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *server = "nope";
char *user = "nope";
char *password = "nope";
char *database = "nope";
unsigned int port = 0;
int cprint(char *text){//Imprime como encabezado el numero de productos sin stock sumado al argumento
MYSQL *conn;
MYSQL_RES *res;
my_ulonglong num;
conn = mysql_init(NULL);
/* Connect to database */
if (!mysql_real_connect(conn, server,
user, password, database, port, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
/* send SQL query */
if (mysql_query(conn, "SELECT id FROM productos WHERE stock <= 0")) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_store_result(conn);
num = mysql_num_rows(res);
printf("\n===============================\n\n");
if(num > 0){
printf("Productos sin stock: %llu\n",num);
}
else{
printf("No hay productos sin stock\n");
}
printf("\n===============================\n\n%s",text);
/*close connection */
mysql_free_result(res);
mysql_close(conn);
return 0;
}
char *remove_newline(char *s)
{
int len = strlen(s);
if (len > 0 && s[len-1] == '\n') // if there's a newline
s[len-1] = '\0'; // truncate the string
return s;
}
int newproduct(){
char *name = malloc(127*sizeof(char));//nombre del producto
char *desc = malloc(127*sizeof(char));//descripcion del producto
double price;//precio del producto
cprint("Agregar nuevo producto\n\n");
printf("Nombre del producto: ");
fgets(name, 127, stdin);
name = remove_newline(name);
printf("Descripcion: ");
fgets(desc, 127, stdin);
name = remove_newline(desc);
printf("Precio: ");
scanf("%e", &price);
MYSQL *conn;
conn = mysql_init(NULL);
printf("Mysql initiated\n");
if (!mysql_real_connect(conn, server,
user, password, database, port, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
printf("connection established\n");
char rname[256];//string donde guardar el nombre con caracteres de escape
char rdesc[256];
printf("Vars declared\n");
mysql_real_escape_string(conn,rname,name,256);//se agregan los caracteres de escape
printf("name escaped\n");
mysql_real_escape_string(conn,rdesc,desc,256);
printf("desc escaped\n");
/*
char *query;//donde guardar el query
snprintf(query,1000,"INSERT INTO productos (nombre,descripcion,stock,precio) VALUES( %s,%s, 0, %e)",rname,rdesc,price);//query a enviar
if (mysql_query(conn, query)) {//enviar el query
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}*/
mysql_close(conn);
printf("Mysql closed\n");
return 0;
}
int main(){
printf("Sales Assistant Alpha v0.0\n");//Nombre y version del programa
unsigned int choice;//numero de eleccion del menu
char *err = NULL;//Error
while(1){//loop infinito
cprint("Menu Principal\n\n");//imprime el encabezado
printf("1-Agregar nuevo producto\n");
printf("2-Editar producto existente\n");
printf("3-Productos sin stock\n");
printf("4-Agregar pedido\n");
printf("5-Salir de la aplicacion\n\n");
if(err != NULL){//evalua si hubo un error y lo imprime
printf("%s\n",err);
err = NULL;
}
printf("Numero de eleccion: ");
scanf("%i",&choice);//pide eleccion
if (scanf("%*[^\n]") != EOF){//read and discard all non-newlines
scanf("%*c"); //then read and discard the newline
}
switch(choice){//evalua la eleccion y ejecuta la funcion correspondiente
case 1:
newproduct();
printf("returned\n");
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
exit(0);//termina el programa
break;
default:
err = "Eleccion no valida";//error
break;
}
}
return 0;
}
And the console execution:
Sales Assistant Alpha v0.0
===============================
Productos sin stock: 3
===============================
Menu Principal
1-Agregar nuevo producto
2-Editar producto existente
3-Productos sin stock
4-Agregar pedido
5-Salir de la aplicacion
Numero de eleccion: 1
===============================
Productos sin stock: 3
===============================
Agregar nuevo producto
Nombre del producto: a
Descripcion: a
Precio: 1
Mysql initiated
connection established
Vars declared
name escaped
desc escaped
Mysql closed
*** stack smashing detected ***: ./sales_assistant terminated
Aborted (core dumped)
------------------
(program exited with code: 134)
Press return to continue
i have this stack smashing thing that is unknown to me. Besides that i want to know how much memory i can safely allocate without getting bus error.
IMPORTANT:when i disable the mysql_real_escape_string functions the code works normally, so the problem is there, but i dont know what the problem is.
thanks, matt.
edited
Added the complete code and translated to english. Also changed the question because i got a new error. Added debugging code.

When you ask for a number with scanf("%i", &choice); (the result of which should be checked!), you leave the newline behind. When you read a line with fgets() in newproduct(), it reads the newline left behind.
Ultimately, if you're doing line-based inputs, use fgets() or readline() (from POSIX 2008) to read the line and sscanf() to parse the line.

your malloc() is wrong for a (char*)
should be:
char *name = malloc(127*sizeof(char));//nombre del producto
char *desc = malloc(127*sizeof(char));

The problem was indeed mysql_real_escape_string(). the thing was that the length argument must be the *from lenght instead of the *to lenght like i was doing. im very happy that i worked that thing out, i was getting really frustrated.

Related

How to connect to db with unixODBC on Ubuntu 20.04 using connector for MySQL 8?

I'm trying for the first time to connect to a local MySQL 8.0 database using ODBC driver.
This is done on a Ubuntu 20.04 machine.
The the code tries to connect to a local database:
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
int main() {
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT stmt;
SQLRETURN ret;
//Definimos el entorno
ret=SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
printf("ret= %d\n", ret);
ret=SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
printf("ret= %d\n", ret);
ret=SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
printf("ret= %d\n", ret);
//Nos conectamos al origen de datos Mysql-odbc
ret = SQLDriverConnect(dbc, NULL, "DSN=MyDSN;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
//ret = SQLDriverConnect("employees", NULL, "DSN=myodbc8a;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
printf("ret= %d\n", ret);
//printf("dbc= %s\n", dbc);
printf("SQL_NTS= %d\n", SQL_NTS);
printf("SQL_DRIVER_COMPLETE= %d\n", SQL_DRIVER_COMPLETE);
char *consulta = "select * from DEPARTMENTS";
SQLSMALLINT nCols = 0;
//SQLINTEGER nFilas = 0;
SQLLEN nFilas = 0;
//SQLINTEGER nIdicator = 0;
SQLLEN nIdicator = 0;
SQLCHAR buf[1024] = {0};
if (SQL_SUCCEEDED(ret)) {
printf("Conectado\n");
SQLAllocStmt(dbc,&stmt);
ret = SQLExecDirect(stmt, consulta, SQL_NTS);
SQLNumResultCols(stmt, &nCols);
SQLRowCount(stmt, &nFilas);
printf("* Numero de Columnas: %u\n", nCols);
//printf("* Numero de Filas: %u \n", nFilas);
printf("* Numero de Filas: %lu \n", nFilas);
while (SQL_SUCCEEDED(ret=SQLFetch(stmt)))
{
printf("\n");
for (int i=1; i<=nCols; ++i)
{
ret = SQLGetData(stmt, i, SQL_C_CHAR, buf, 1024, &nIdicator);
if (SQL_SUCCEEDED(ret))
{
printf("* Columna %s", buf);
}
}
}
printf("\n");
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
SQLDisconnect(dbc);
} else { printf("NO HA SIDO POSIBLE LA CONEXION\n"); }
return 1;
}
The code compiles ok but it does not connect to the db for some reason.
profe#profe-VirtualBox:~/Downloads$ gcc conexion.c -o conexion -lodbc
-std=gnu99 profe#profe-VirtualBox:~/Downloads$ ./conexion
ret= 0 ret= 0 ret= 0
ret= -1
SQL_NTS= -3
SQL_DRIVER_COMPLETE= 1
NO HA SIDO POSIBLE LA CONEXION
These are my odbcinst.ini and odbc.ini files:
profe#profe-VirtualBox:~$ cat /etc/odbcinst.ini
[MySQL ODBC 8.0 Driver]
Driver=/usr/local/lib/libmyodbc8w.so
UsageCount=1
[MySQL ODBC 8.0]
Driver=/usr/local/lib/libmyodbc8a.so
UsageCount=1
profe#profe-VirtualBox:~$ cat /etc/odbc.ini
[MyDSN]
Description = Your MySQL database
Driver = MySQL ODBC 8.0 Unicode Driver
Server = 127.0.0.1
User = root
Password = ASIR2
Port = 3306
Database = employees
profe#profe-VirtualBox:~$

How to store a value from a MySQL database in a C variable

I'm starting with C and MySQL, I have created a database with some columns and I want to store two of them and use it in other parts of the code. In the example that I give i'm trying to store one value of "latitud" from de database in variable float lat, but it give me an error in the core. Do you know how can I solve this? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#define HOST "localhost"
#define USER "victor"
#define PASS "tfg"
#define DATABASE "barcos"
int main (int argc, char *argv[]){
MYSQL *con;
MYSQL_ROW row;
MYSQL_RES *res;
con = mysql_init(NULL);
if (!mysql_real_connect(con, HOST, USER, PASS, DATABASE, 0, NULL, 0)){ // CONEXIÓN A LA BASE DE DATOS
fprintf(stderr, "%s\n", mysql_error(con));
return 1;
}
mysql_query(con, "SELECT latitud FROM BARCOS ");
res = mysql_store_result(con);
printf("latitud:\n");
while((row = mysql_fetch_row(res)) !=0)
printf("%s\n", row[0]);
float lat = row[0] ? atof(row[0]) : 0.0;
printf("%f", lat);
mysql_free_result(res);
mysql_close(con);
return 0;
}
What is res after
res = mysql_store_result(con); // res could be NULL, you do not check the result
Then you fetch all rows and print them
while((row = mysql_fetch_row(res)) !=0) // no braces, that means, ...
printf("%s\n", row[0]); // print only the first element from each row
but afterwards you call
//row is NULL here, because you exhausted the set in the loop before
float lat = row[0] ? atof(row[0]) : 0.0;
and you cannot dereference a NULL pointer.
From mysql_store_result:
Return Values
A pointer to a MYSQL_RES result structure with the results. NULL if the statement did not return a result set or an error occurred.
From mysql_fetch_row:
Return Values
A MYSQL_ROW structure for the next row, or NULL (either if there are no more rows or when an error occurred).

C - alternative using snprintf to prepare MySQL statements?

I've been tearing my hair out for a while on this one. The C code is called from a bash script, which loops through a command's output in a while loop and passes variables to the C script as args. It goes through a list and partitions data properly. I've been using the C MySQL api, and up until now everything has been relatively straight forward. It tries to run a SELECT(EXISTS) command to dictate whether to input a new row, or update an existing one.
I have typed the command into MySQL terminal and it works perfectly. I have even printf'd it and copied the command directly into the terminal. It works....
So why then, am I getting Syntax errors? I've tried escaping fields and input using backticks, single quotes and double quotes and I'm still getting this dumbounding error. I thought maybe it was something to do with the null space? But I'm at my witts end. Here's the code, any advice would be greatly appreciated :)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mysql/mysql.h>
const int MAXLEN = 100;
/* Compile with:
gcc db.connect.c `mysql_config --libs` -O1
for the best results
*/
/* Function definitions for later */
void finish_with_error(MYSQL *con);
int send_query(MYSQL *con, char query[MAXLEN]);
/* If any SQL commands fail, return an error message */
void finish_with_error(MYSQL *con)
{
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(1);
}
/* Helper function to send queries to MySQL database */
int send_query(MYSQL *con, char query[MAXLEN])
{
if (mysql_query(con, query)) {
finish_with_error(con);
}
return 0;
}
int main(int argc, char ** argv)
{
// Establish MySQL API connection, if not- fail with err
MYSQL *con = mysql_init(NULL);
if (con == NULL) {
finish_with_error(con);
}
// Connection string.
if (mysql_real_connect(con, "localhost", "user", "password",
NULL, 0, NULL, 0) == NULL){
finish_with_error(con);
}
if (argv[1] == NULL){
printf("No query passed, terminating script \n");
return 1;
}
if (argv[1] != NULL) {
if( strcmp( argv[1], "--help" ) == 0 ) {
printf("This program was created to interact with MySQL, by checking and updating live network stats\n");
printf("It has 2 parameters, an IP address to look in the database for and a value to update a field by, \
if that IP address is found. ");
printf("If the value is not found, the program will insert a new row.");
return 1;
}
// Works out how much memory to allocate to buffer for snprintf
// Originally cmd_len was 65- as this was the amount of bits needed by the address string.
// This was changed to MAXLEN to prevent SEGFAULTS and give the function breathing room.
size_t cmd_len = MAXLEN;
size_t param_len = sizeof(argv[2]);
size_t q_len = cmd_len + param_len;
// Allocates that memory to a buffer, referenced as query
char *query = malloc(sizeof(char) * q_len);
snprintf(query, q_len, "SELECT EXISTS(SELECT * FROM `analytics`.`live` WHERE `foreign_addr` = `%s`)", argv[1]);
printf("%s\n", query);
send_query(con, query);
free(query);
// Used to store the result of the MySQL select commands
MYSQL_RES *result = mysql_store_result(con);
if (result == NULL) {
finish_with_error(con);
}
// num_fields stores the number of fields, i and x are counters, answer is 1 or 0
int num_fields = mysql_num_fields(result);
int i = 0;
// Loops through each row in the answer statement.
// There will only be one row in the answer, which will be 1 or 0
// Basically, if the IP is found.
MYSQL_ROW row;
while ((row = mysql_fetch_row(result))){
for (i=0; i<num_fields; i++) {
// If the IP isn't in the table
if(!atoi(row[i]))
send_query(con, argv[1]);
// If the IP is already in the table
if(atoi(row[i])) {
snprintf(query, q_len, "UPDATE analytics.live SET count=count+1 WHERE foreign_addr = '%s'", argv[1]);
printf("%s\n", query);
free(query);
snprintf(query, q_len, "UPDATE analytics.live SET dat_sent = dat_sent + %s", argv[2]);
printf("%s\n", query);
free(query);
}
}
}
mysql_close(con);
return 1;
}
mysql_close(con);
return 0;
}

connect remote sql (c language)

I cant connect remote mysql server. After I running the code use gcc, there is undefined reference to mysql
administrator#el6116-1:~$ gcc pilihan.c -o pilihan /tmp/cc4UQV0F.o: In
function `main': pilihan.c:(.text+0x67): undefined reference to
mysql_init' pilihan.c:(.text+0xe1): undefined reference to
mysql_real_connect' pilihan.c:(.text+0xf6): undefined reference to
mysql_error' pilihan.c:(.text+0x135): undefined reference to
mysql_query' pilihan.c:(.text+0x145): undefined reference to
mysql_error' pilihan.c:(.text+0x177): undefined reference to
mysql_use_result' pilihan.c:(.text+0x1c2): undefined reference to
mysql_fetch_row' pilihan.c:(.text+0x1d9): undefined reference to
mysql_free_result' pilihan.c:(.text+0x1e5): undefined reference to
mysql_close' collect2: error: ld returned 1 exit status
And here is my code in c:
#include <stdio.h>
#include <mysql/mysql.h>
#include <stdlib.h>
void DataA()
{
printf( "DataNasabah Dipilih..." );
}
void DataB()
{
printf( "AdminNasabah Dipilih..." );
}
main() {
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
char *server = "167.205.65.251";
char *user = "nasabah";
char *password = "123";
char *database = "wordpress";
conn = mysql_init(NULL);
int input;
printf("MySQl Client Alfred Saut Sibarani 23214038\n");
printf( "1. Data A\n" );
printf( "2. Data B\n" );
printf( "3. Keluar\n" );
printf( "Pilih Database: " );
scanf( "%d", &input );
/* Connection to Database */
if (!mysql_real_connect(conn, server,
user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
/*If input =2 send mysql query*/
if (input == 2 && mysql_query(conn, "SELECT * FROM DataNasabah"))
{
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_use_result(conn);
/* Show table output*/
printf("Data Nasabah:\n");
while ((row = mysql_fetch_row(res)) != NULL)
printf("%s %s %s\n", row[0],row[1],row[2]);
/* Close connection */
mysql_free_result(res);
mysql_close(conn);
}
#include <mysql/mysql.h>
Did not succeed. You will have to make sure the library is in place and is beeing properly linked.
undefined reference to
mysql_init' pilihan.c:(.text+0xe1)
Is a clear indicator that your linking of the library mysql.h failed.

C program to add data to MYSQL database - No results added

I'm trying to build a C-program to add data to my MYSQL database and I would like to use variables within the SQL string. I want to insert UNIX time (epoch) in one column and the result from an energy meter into the other (double)
Even though it builds without errors or warnings I can't get it to insert the data into the table. Can someone give me a hint of where to look?
Thankful for all help I can get as I'm pretty much fumbling in the dark
Regards,
Mikael
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <mysql.h>
#include <my_global.h>
#include <stdlib.h> // For exit function
int loggingok; // Global var indicating logging on or off
double result = 323.234567; //Debug
double actual_time_sec;
void calculate_watts(void)
{
MYSQL *conn = mysql_init(NULL);
char *server = "localhost";
char *user = "root";
char *password = "password"; /* set me first */
char *database = "power";
char SQL_String[100];
char time_char[11];
char result_char[11];
time_t actual_time;
actual_time = time(0);
actual_time_sec = difftime(actual_time,0);
sprintf(time_char,"%g",actual_time_sec);
sprintf(result_char,"%g",result);
printf("Tid: %g\n",actual_time_sec); //Debug
printf("Resultat: %g\n", result); //Debug
strcpy(SQL_String, "INSERT INTO consumption(time,consumption) VALUES(");
strcat(SQL_String, time_char);
strcat(SQL_String, ",");
strcat(SQL_String, result_char);
strcat(SQL_String, ")");
printf("SQL: %s", SQL_String); //Debug
// SQL_String = "INSERT INTO consumption(time,consumption) VALUES('"+ actual_time_sec +"',"+ result +")";
if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1); }
if (mysql_query(conn, SQL_String)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1); }
}
int main (int argc, char *argv[])
{
printf(argv[1]); //Debug
if(strcmp(argv[1], "db")) {
loggingok=1;
printf("Efergy E2 Classic decode \n\n");
calculate_watts(); }
else {
loggingok=0; }
return 0;
}
here is a great example...
http://php.net/mysql_query. Note the usage of sprintf here. The 2nd and 3rd parameters work with the sprintf to place the data in these 2 parameters exactly where they are needed in the SQL statement.
$query = sprintf("SELECT firstname, lastname, address, age FROM friends
WHERE firstname='%s' AND lastname='%s'",
mysql_real_escape_string($firstname),
mysql_real_escape_string($lastname));
// Perform Query
$result = mysql_query($query);
// Check result
// This shows the actual query sent to MySQL, and the error. Useful for debugging.
if (!$result) {
$message = 'Invalid query: ' . mysql_error() . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
Please note the usage of if (!$result) this allows you to do a quick validation of if you have success or not. If an error is found the text resturned from mysql_error is placed in the message variable and then presented when the app dies.