I am trying to query a database using the libmysql++ API and so far I am able to successfully run some queries. (reason behind some will be explained later)
So everything works fine, but as soon as I attempt at closing the connection and exiting the program, a Segmentation fault (core dumped) appears, as you can see below:
shell> g++ -o test testCDB.cpp -L/usr/include/mysql -lmysqlclient -I/usr/include/mysql
testCDB.cpp: In function ‘int main(int, char**)’:
testCDB.cpp:122:74: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
StudentManager manager1("localhost", "root", "ikilledkennedy.", "testDB");
^
testCDB.cpp:122:74: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
testCDB.cpp:122:74: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
testCDB.cpp:122:74: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
shell> ./test
Successfully connected to the database.
Enter your query: SHOW DATABASES;
[information_schema]
[mysql]
[performance_schema]
[sys]
[testDB]
Do you wish to continue?(Y:1/N:0) : 1
Enter your query: SHOW TABLES;
[Student]
Do you wish to continue?(Y:1/N:0) : 0
Segmentation fault (core dumped)
shell>
What's causing this issue and what measures do I take to resolve this?
Coming to the some queries part--there are certain queries that exit with a Segmentation fault too when fed to the database (like INSERT) which I feel is because these queries don't produce a result set and when I try to fetch rows in displayTable() or perhaps free the result set in performQuery(char *), a NULL value is encountered. Am I right in thinking this or is there some other root cause?
The code is as follows:
#include <iostream>
#include <string>
#include <mysql.h>
#include <limits>
using namespace std;
class StudentManager
{
private:
char *host;
char *user;
char *password;
char *database;
MYSQL *connection;
MYSQL_RES *result;
void init()
{
connection = mysql_init(NULL);
if(!mysql_real_connect(connection, host, user, password, database, 0, NULL, 0))
{
cout << "Cannot connect to the database.\n"
<< "Please make sure you have entered the details correctly and try again."
<< endl;
}
else
{
cout << "Successfully connected to the database.\n"
<< endl;
}
}
void displayTable()
{
MYSQL_ROW row;
unsigned int num_fields;
unsigned int i;
num_fields = mysql_num_fields(result);
cout << endl;
while((row = mysql_fetch_row(result)))
{
for(i = 0; i < num_fields; i++)
{
cout << "[" << ( row[i] ? row[i] : "NULL" ) << "]";
}
cout << endl;
}
cout << endl;
}
public:
StudentManager(char *host, char *user, char *password, char *database)
{
this->host = host;
this->user = user;
this->password = password;
this->database = database;
init();
}
void performQuery(char *query)
{
if(mysql_query(connection, query))
{
cout << "Query error: "
<< mysql_error(connection)
<< endl;
return;
}
result = mysql_use_result(connection);
displayTable();
mysql_free_result(result);
}
void disconnect()
{
cout << "Closing connection...";
mysql_close(connection);
cout << "Connection successfully closed.";
}
};
int main(int argc, char *argv[])
{
StudentManager manager1("localhost", "foo", "bar", "testDB");
int choice = 1;
char *query;
while(1)
{
cout << "Enter your query: ";
cin.getline(query, 256);
manager1.performQuery(query);
cout << "Do you wish to continue?(Y:1/N:0) : ";
cin >> choice;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
if(choice < 1)
{
manager1.disconnect();
break;
}
}
return 0;
}
You use uninitialized pointer here:
char *query;
while(1)
{
cout << "Enter your query: ";
cin.getline(query, 256);
The query variable is not initialized, and points to some random memory location. Most likely somewhere in the stack segment. When you write to that location using getline you corrupt the stack. Which leads to segmentation fault.
Since the code in question does not seem to be performance critical I'd suggest to rewrite the code like this:
std::string line;
while (cin.good())
{
cout << "Enter your query: ";
std::getline(cin, line);
PS there are some other issues with the code in my opinion, but since the question is about segmentation fault I'll keep my answer focused.
Looks like memory corrupted early, here:
char *query; // <-- uninitialized buffer
while(1)
{
cout << "Enter your query: ";
cin.getline(query, 256);
getline reads data from the stream and stores it into the buffer. Buffer of proper length should be allocated by you. To fix it use:
char query[256];
there are certain queries that exit with a Segmentation fault too when fed to the database (like INSERT) which I feel is because these queries don't produce a result set
INSERT query doesn't produce result set, so according to the documentation mysql_fetch_row(result) returns NULL. It's the correct behavior and not a reason of Segmentation fault.
Related
I'm new to C++, and I'm trying to write a project that interacts through command line. Right now, whenever I run my main (which is the executable), I always receive a segmentation fault error when the main program finished.
Edit comment:
I'm told by tutor to use as little as C++ features such as vectors or strings ... I'm also very new to C++, so i'm trying to utilize as many basic C functions as I can.
I'm
My main function looks like this:
int main(int argc, char** argv) {
cout << "starting mvote..." << endl;
int run_flag = 1;
char* actionBuffer = (char*)malloc(100 * sizeof(char));
char* action = (char*)malloc(16 * sizeof(char));
char* readPtr;
char exit[4] = { 'e','x','i','t' };
//parse command line argumentand get the filename
char* filename = argv[2];
cout << filename;
FILE* fp;
char line[64];
//from here, I'm opening the file and read it by lines
fp = fopen(filename, "r");
if (fp == NULL) {
cout << "file not exists";
return -1;
}
while (fgets(line, 64, fp) != NULL) {
cout << line << "\n";
}
fclose(fp);
while (run_flag == 1) {
cout << "what do you want?\n " << endl;
cin.getline(actionBuffer, 1024);
if (strcmp(actionBuffer, exit) == 0) {
cout << "bye!";
run_flag = 0;
break;
}
//if not exit, Look for the space in the input
readPtr = strchr(actionBuffer, ' ');
int size = readPtr - actionBuffer;
//extract the operation
strncpy(action, actionBuffer, size);
for (int i = 0; i < size; i++) {
cout << "operation:" << action[i];
}
// depend on the operation specified before the first empty space
run_flag = 0;
}
free(actionBuffer);
free(action);
return 0;
}
Description:
I first try to open up a csv file which lies in the same folder as main, and I read the file line by line. Then, I just implement a simple command where you can type exit and quit the program.
I allocate two memory, actionBuffer and action, which are used to hold command
Problem: a segmentation fault [core dumped] always exists when I type exit and hit enter, and then the process finished.
Research: So I learned that segmentation fault is due to accessing a memory that does not belongs to me. But where in my program am I trying to access such a memory?
Any advice is appreciated! Thank you.
Just to give you an idea, this would be an example of C++ code
#include<iostream>
#include<fstream>
#include<string_view>
#include<string>
#include<sstream>
#include<exception>
int main(int argc, char** argv) {
std::cout << "starting mvote...\n";
//parse command line argumentand get the filename
std::string filename = argv[2]; // NO CHECKS!
std::cout << filename <<'\n';
//from here, I'm opening the file and read it by lines
{
std::ifstream ifs(filename);
if (!ifs) {
throw std::invalid_argument("file not exists");
}
std::string line;
while (std::getline(ifs, line)) {
std::cout << line << '\n';
}
}
bool run_flag = true;
while (run_flag) {
std::cout << "what do you want?\n";
std::string userInput;
std::getline(std::cin, userInput);
if (userInput == "exit") {
std::cout << "bye!\n";
return 0;
}
std::stringstream userInputSs(userInput);
std::string operation;
while(userInputSs >> operation){
std::cout << "operation: " << operation << '\n';
}
}
}
I have written a small C++ program to set a property in a text file. The implementation is as following:
#include <cstdio>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
const string PROPFILE = "./propfile";
const string TEMPFILE = PROPFILE + ".tmp";
int setProp(const string &key, const string &val) {
try {
ifstream original(PROPFILE, ios::in);
ofstream tempfile(TEMPFILE, ios::out | ios::trunc);
for (string line; getline(original, line); ) {
if (line.compare(0, key.size(), key) == 0 && line[key.size()] == '=') {
tempfile << key << '=' << val << endl;
} else {
tempfile << line << endl;
}
}
cout << "original.rdstate()" << original.rdstate() << endl;
original.close();
tempfile.close();
} catch (ifstream::failure e) {
cerr << e.what() << endl;
}
if (rename(TEMPFILE.c_str(), PROPFILE.c_str()) != 0) {
cout << "Could not move " + TEMPFILE << "to " << PROPFILE << endl;
return 1;
}
return 0;
}
int main(int argc, const char *argv[]) {
try {
return setProp(argv[1], argv[2]);
} catch (logic_error) {
cout << "Invalid args" << endl;
return 1;
}
}
However, when I try to compile and execute it from commandline via ./a.out TESTPROP TESTVALUE, the value IS set as expected in propfile but rdstate() returns 6 (which means failbit and eofbit are set), I can't understand why are they getting set, can somebody explain ?
Contents of propfile before running ./a.out TESTPROP TESTVALUE are:
TESTPROP=NOTHING
After running the progam:
TESTPROP=TESTVALUE
I'm just a student, please don't mind if it's a dumb question :)
This is expected behaviour, the failbit is set whenever there is a failure to read the expected value. Even if that failure is because of end of file.
For instance see here
If no characters were extracted for whatever reason (not even the
discarded delimiter), getline sets failbit and returns.
I'm trying to exchange messages using multiple covert channels.
So, basically, first i need to select the channel that i want to use for communication and then select the "destination_ip" of the user that i want to chat with and after that the
processMessage()
is called. Now, to move from one channel to another I have to close the existing connection and then open a new connection with the new channel that i want to use. My code below is modified to keep using the same channel after closing the connection and contain only the things that you need.
#include <channelmanager.hpp>
#include <thread>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <openssl/hmac.h>
struct CommunicationFixture {
CommunicationFixture() {
channelmanager.setErrorStream(&cout);
channelmanager.setOutputStream(&cout);
destination_ip = "";
channel_id = channelmanager.getChannelIDs()[0];
}
library::ChannelManager channelmanager;
vector<string> last_adapters;
string destination_ip;
string channel_id = "";
int processMessage(string message) {
if (message.compare("exit") == 0) {
channelmanager.closeConnection(destination_ip);
return 1;
}
vector<string> arguments;
boost::split(arguments, message, boost::is_any_of(" "), boost::token_compress_on);
if (arguments[0].compare("argument") == 0) {
if (arguments.size() < 2) {
cout << "Not enough arguments" << endl;
return 0;
}
string argument_list = arguments[1];
for (unsigned int i = 2; i < arguments.size(); i++) {
argument_list += " " + arguments[i];
}
channelmanager.setChannelArguments(destination_ip, argument_list);
cout << "Set channel argument to '" << argument_list << "'." << endl;
return 0;
}
if (message.compare("help") == 0) {
cout << "Help not available in chat mode. Close chat first with 'exit'" << endl;
return 0;
}
channelmanager.openConnection(destination_ip, channel_id);
channelmanager.sendMessage(destination_ip, message);
return 0;
}
int close(string destination){
cout << "closing.." << endl;
channelmanager.closeConnection(destination); //I believe i have the error because of this!
return 0;
}
};
BOOST_FIXTURE_TEST_SUITE(communication, CommunicationFixture)
BOOST_AUTO_TEST_CASE(basic_communication) {
selectAdapterId(0);
cout << "Test" << endl << endl;
printCommands();
cout << "Enter your command:" << endl;
string command;
int code = 0;
while (code != 2) {
std::getline(cin, command);
code = processCommand(command);
if (code == 1) {
// chat
cout << "chat started.." << endl;
int chatCode = 0;
while (chatCode != 1) {
std::getline(cin, message);
close(destination_ip);
chatCode = processMessage(message);
channelmanager.setErrorStream(&cout);
}
cout << "chat ended." << endl;
}
}
}
BOOST_AUTO_TEST_SUITE_END()
Note that, i think that the error happens due to the
function close()
because without it i don't get any errors. and the error doesn't happen immediately but after exchanging some messages. Here's the error:
unknown location(0): fatal error: in
"communication/basic_communication": memory access violation at
address: 0x00000024: no mapping at fault address
communicationTest.cpp(325): last checkpoint: "basic_communication"
test entry
Memory access violation happen when you are trying to access to an unitialized variable, in this case the channelmanager.
I can only see that you initialize channelmanager in the processMessage() method and you are closing the connection before initializing the channelmanager as it happen in:
close(destination_ip);
chatCode = processMessage(message);
Either you change the initialization or do not close it before the processMessage() method.
Memory access violation is also called a segmentation fault (or segfault), occurs when the program tries to access a memory location that doesn't exist, or is otherwise inaccessible. We call this trying to access an illegal memory location. That memory is either non-existent or we aren't aren't allowed to touch it.
If the first input from user is 'exit', which is going to call
if (message.compare("exit") == 0) {
channelmanager.closeConnection(destination_ip);
return 1;
}
In this case, destination_ip isn't initialised.
EDIT: I started from scratch, going with a user+pass authentication for better security.
I posted a new question here.
I'm writing a program that checks that the computer running it has a specific hostname (as an authentication method).
#include <iostream>
using namespace std;
void RUN()
{
//Do stuff
}
char const* HOSTNAME
int auth()
{
if (HOSTNAME = getenv("HOSTNAME"))
{
HOSTNAME = getenv("HOSTNAME");
return 0;
}
else if(HOSTNAME = getenv("COMPUTERNAME"))
{
HOSTNAME = getenv("COMPUTERNAME");
return 0;
}
else
{
return 1;
};
}
int main()
{
cout << "Authenticating..." << endl; auth();
if (HOSTNAME == "Craptop")
{
cout << "Success!" << endl;
RUN();
}
else
{
cout <<
cout << "Authentication failed! Exiting..." << endl;
exit(0);
};
return 0;
}
Im getting this error: (should be the initializer but seams to act like a variable)
./EX_host_locked.cpp:5:1: error: expected initializer before ‘int’
int auth()
^~~
since int acts like a variable, auth is uninitialized and causing more errors later.
How can I make int be the initializer for auth? Also how could I generally improve my code (for security/stability)?
You are missing ; after line following line:
char const* HOSTNAME
So you are getting the error. Put ; and make it:
char const* HOSTNAME;
I am new to Protocol Buffers and inexperienced with C++, I am trying to complete the tutorial at https://developers.google.com/protocol-buffers/docs/cpptutorial
I've created the proto file mentioned in the tutorial and gotten addressbook.pb.h and addressbook.pb.cc from this proto. I am trying to follow the segment "Writing A Message", so I copied and pasted the following code from the tutorial. I immediately run into an issue in the main function, which I'll explain below:
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phone();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_person());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
In the main function the code exits without prompting for any inputs due to this portion:
if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}
which appears as one of the first few lines in the function, before any inputs are requested. I read that argc will be the number of inputs. I'm confused because I copied and pasted exactly what the tutorial wrote, but it doesn't appear to be running correctly.
That code expects a file name to be passed on the command line, not read from stdin. You've not specified what platform you're on, but you'll do something like my_program.exe C:\some\file\somewhere on Windows or ./my_program /some/file/somewhere on Linux/Mac/Other Unix like OS. If you're running the program from your IDE's run/debug function then you'll need to configure it to pass the name of the file as a command line argument. How to do that will depend on what IDE you're using.