Variable change without any direct action - c++

I have wrote an API as defined below. This API is used to find the index of a filename in a file system. The filesystem is coming from an Android device through mtp. What I'm doing is to request a list of files stored on the Android device and compare each file listed to the one I'm looking for 'name2look'
I have created a vector table to store what I'm doing but it's not mandatory. My concerns is that the variable name2look contain the right name I'm looking for "Pictures"
uint32_t USBDevice::GetIndexFromName(LIBMTP_mtpdevice_t *dev, uint32_t storage,const char *name2look)
{
uint32_t idx_fold = 1;
std::vector<MyFileTreeItem*> FSimage;
LIBMTP_file_t *files;
LIBMTP_file_t *file;
std::cout << "NAME : " << name2look << "\n";
files = this->GetFileAndFolder(dev, storage,0);
file = files;
while (file != NULL) {
MyFileTreeItem* FSitem = new MyFileTreeItem();
FSitem->filename = file->filename;
FSitem->index = file->item_id;
FSitem->FileType = file->filetype;
FSimage.push_back(FSitem);
std::cout << "NAME : " << name2look << "\n";
std::cout << "FS NAME : " << file->filename << "\n";
if(std::strcmp(file->filename, name2look)==0) {
std::cout << "FIND IDX : " << file->item_id << "\n";
return file->item_id;
}
file = file->next;
}
return 0;
}
The Log is showing that the first display 'std::cout' is ok. the variable name is still 'Pictures' but when I ask to display it after in the "while" the variable name2look change and is not the same anymore.
First display
NAME : Pictures
second one in the while
NAME : Martin).mp3
FS NAME : Music
How is it possible to be corrupted ??
The function is called by a Qt C++ code:
void MyButtonGroup::buttonClick(QAbstractButton *button)
{
uint32_t status;
QList<QTreeWidgetItem *> itemList;
uint32_t index = 0;
if (button->text() == "Create Folder") {
itemList = this->MyTree->selectedItems();
QString str = itemList[0]->text(0);
char *utf8_text = str.toLatin1().data();
if(utf8_text != NULL)
{
std::cout << "A CHERCHER " << utf8_text << "\n";
index = this->MyDevice.GetIndexFromName(this->dev_id, storage->id, utf8_text);
}
else
index = 0;
CreateFolderDialog *dialog = new CreateFolderDialog(this->MyTree, this->MyDevice, this->dev_id, this->storage, index);
dialog->show();
}
utf8_text report the right value.
Any idea ?

This might be the problem. I am not sure. Check it out.
This line:
char *utf8_text = str.toLatin1().data();
What does the documentation say toLatin1() does? It creates a new QByteArray object and then you call data() on that and you get a pointer to character and then the QByteArray is destroyed at the end of the line because it was TEMPORARY.
And now you have an invalid pointer to freed memory that you then pass into your function. It probably gets overwritten by the first call to new() in your function.
I think you should change it to something like this:
QByteArray latin_str = str.toLatin1();
char *utf8_text = latin_str.data();
Your name utf8_text is weird since you just converted it to Latin1 which isn't UTF8.

Related

Providing initial text for the readline buffer

In a readline buffer I want to provide an initial value the user can edit. This can either be a default value or the old value of the field already saved to my database. The entered value shall not be added to the readline-history as it is only "data" not a command.
From the samples here and on the internet I have learned that this code should do the job:
char *deftext;
int MatCustom::set_deftext ()
{
// cout << "set_deftext called ... deftext: " << deftext << endl;
if (deftext)
{
// cout << "inserting..." << endl;
rl_insert_text(deftext);
// rl_line_buffer = deftext;
// cout << rl_stuff_char('J') << endl;
rl_redisplay();
deftext = (char *)NULL;
rl_startup_hook = (rl_hook_func_t *)NULL;
// rl_pre_input_hook = (rl_hook_func_t *)NULL;
};
return 0;
}
string MatCustom::getlineWithoutHistory(const string &field) {
string returnString;
const char *buffer;
char *cstr = new char[field.length() + 1];
strcpy(cstr, field.c_str());
deftext = cstr;
// cout << "Deftext in getLineWithoutHistory: " << deftext << endl;
rl_startup_hook = set_deftext;
// rl_pre_input_hook = set_deftext;
buffer = :: readline("");
if (buffer != nullptr) {
returnString = buffer;
} else {
returnString = "";
}
free((void *) buffer);
delete [] cstr;
return returnString;
}
It works perfectly well to convert my old value to a char* and pass it to the global variable deftext, because a parameter cannot be given to the readline-hook-functions.
I am experiencing problems: Whenever I use the rl_startup_hook, which is said to be called before the prompt gets printed, I find this this hook never gets executed. However, when I use the rl_pre_input_hook, which is called prior to the input to begin, my function set_deftext actually gets called. This functions finds deftext set.
Still, I don't get any text inserted into the input buffer. The function rl_insert_text produces no change – even when I use rl_redisplay(). Directly changing the buffer with rl_line_buffer = deftext; also has no effect. When I try cout << rl_stuff_char('J') << endl; for debugging just to insert a single char, nothing happens and the function returns 0 indicating an unsuccessful insert.
Both functions are static member functions. I usually call my function with
input = MatCustom::getlineWithoutHistory(rawValue);
to edit to provided value (rawValue).

Why does creating 2 variables cause a crash in custom STL, C++ VS2019?

Hello I'm trying to rewrite my own memory manager and STL (nothing fancy, just some basic vector and string features) and I'm getting a strange behaviour. I'm trying to get experience in the memory management field because I'm a high school student with time to spare. The problem is, when I create my first variable everything goes perfectly but after creating the second variable, the program crashes while creating the first variable.
String.h/.cpp
class String {
char* pointer_toBuffer = nullptr;
size_t buffer_length = 0;
IAllocator* Allocator;
public:
String(const char* text, IAllocator* Allocator);}
String::String(const char* text, TuranAPI::MemoryManagement::IAllocator* MemoryAllocator) : Allocator(MemoryAllocator) {
std::cout << "String creation has started: " << text << std::endl;
unsigned int i = 0;
while (text[i] != 0) {
i++;
}
buffer_length = i + 1;
pointer_toBuffer = (char*)Allocator->Allocate_MemoryBlock(buffer_length * sizeof(char));//When I write the Second String part, FirstString crashes directly. I use VSDebug and it says access violation here while creating FirstString. It is successful if I delete the SecondString part.
for (unsigned int letterindex = 0; letterindex < i; letterindex++) {
pointer_toBuffer[letterindex] = text[letterindex];
}
pointer_toBuffer[i] = 0;
}
MemoryManagement.h/cpp
TAPIMemoryAllocator::TAPIMemoryAllocator(MemoryBlockInfo MemoryPool_toUse){
std::cout << "TAPIMemoryAllocator is created!\n";
std::cout << "MemoryPool's start pointer: " << MemoryPool_toUse.address << std::endl;
MemoryPool.address = MemoryPool_toUse.address;
MemoryPool.size = MemoryPool_toUse.size;
SELF = this;
}
void* TAPIMemoryAllocator::Allocate_MemoryBlock(size_t size) {
std::cout << "MemoryPool's start pointer: " << MemoryPool.address << std::endl;
std::cout << "A buffer of " << size << " bytes allocation request found in TAPIMemoryAllocator!\n";
if (SELF == nullptr) {
TMemoryManager First(1024 * 1024 * 1024 * 1);
MemoryBlockInfo FirstMemoryBlock;
FirstMemoryBlock.address = SELF->MemoryPool.address;
FirstMemoryBlock.size = size;
Allocated_MemoryBlocks[0] = FirstMemoryBlock;
return (char*)SELF->MemoryPool.address;
}
void* finaladdress = SELF->MemoryPool.address;
for (unsigned int blockindex = 0; blockindex < MAX_MEMORYBLOCKNUMBER; blockindex++) {
MemoryBlockInfo& MemoryBlock = Allocated_MemoryBlocks[blockindex];
finaladdress = (char*)finaladdress + MemoryBlock.size;
if (size <= MemoryBlock.size && MemoryBlock.address == nullptr) {
std::cout << "Intended block's size is less than found memory block!\n";
MemoryBlock.address = finaladdress;
//You shouldn't change Memory Block's size because all of the allocations before this are based upon the previous size!
//You should move all the previous allocated memory to set the size (which is not ideal!)
//If I'd want to find memory leaks causing this, I could write code here to log the leaks!
return MemoryBlock.address;
}
else if (MemoryBlock.size == 0 && MemoryBlock.address == nullptr) {
std::cout << "An empty block is created for intended block! Block's Array index is: " << blockindex << "\n";
std::cout << "MemoryPool's start pointer: " << MemoryPool.address << std::endl << "MemoryBlock's pointer: " << finaladdress << std::endl;
//This means this index in the Allocated_MemoryBlocks has never been used, so we can add the data here!
MemoryBlock.address = finaladdress;
MemoryBlock.size = size;
return MemoryBlock.address;
}
}
//If you arrive here, that means there is no empty memory block in the Allocated_MemoryBlocks array!
std::cout << "There is no empty memory block in the Allocated_MemoryBlocks array, so nullptr is returned!\n";
return nullptr;
}
TMemoryManager::TMemoryManager(size_t Main_MemoryBlockSize) {
if (SELF != nullptr) {
std::cout << "You shouldn't create a MemoryManager!";
return;
}
std::cout << "TMemoryManager is created!\n";
MainMemoryBlock.address = malloc(Main_MemoryBlockSize);
MainMemoryBlock.size = Main_MemoryBlockSize;
SELF = this;
std::cout << "Main Memory Block's start pointer: " << MainMemoryBlock.address << std::endl;
MemoryBlockInfo TuranAPI_MemoryPool;
TuranAPI_MemoryPool.address = MainMemoryBlock.address;
std::cout << "TuranAPI_MemoryPool.address: " << TuranAPI_MemoryPool.address << std::endl;
TuranAPI_MemoryPool.size = 1024 * 1024 * 10;
TAPIMemoryAllocator Create(TuranAPI_MemoryPool);
}
TMemoryManager* TMemoryManager::SELF = nullptr;
TMemoryManager First(1024 * 1024 * 1024 * 1);
Main.cpp
String FirstString("How are you?", TAPIMemoryAllocator::SELF);
std::cout << FirstString << std::endl; //If I delete the below, it prints "How are you?" as expected
String SecondString("I'm fine, thanks!", TAPIMemoryAllocator::SELF);
std::cout << SecondString << std::endl;
Solved: The problem was in Allocator. When allocator goes out of scope, it's Allocate_MemoryBlock function (it's a virtual function, not static) is deleted. I don't know why it doesn't occur when only one String is created (maybe a compiler optimization) but storing Allocator's itself (All of variables was static already) and assinging SELF as stored one's pointer solved the problem.

QTextStream write data in file

I'm learning QtCreator and having troubles writing data in file. Here's some code :
char *str;
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2) {
str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
std::cout << str << std::endl;
out << str << "\n";
i += 2;
}
getItem returns a QWidget * from a QFormLayout filled with QLineEdit (that explains the dynamic cast). Anyway, when I pass str into std::cout it works fine, the data is printed, but when I pass str into out, it writes only the first char of str in the file.
I don't get what I'm doing wrong, I really would appreciate any tips.
This line is a problem: str = dynamic_cast<QLineEdit *>(this->getItem(i))->text().toLocal8Bit().data();
dynamic_cast<QLineEdit *>(this->getItem(i))-> is OK
->text() creates a temporary QString
.toLocal8Bit() creates a temporary QByteArray
.data() returns a pointer to the internal data of the QByteArray
As soon as the line is passed the QByteArray will be destroyed and you have a dangling pointer. str points to invalid data.
Everything you do with this pointer afterwards (except letting it point to somewhere else) is undefined behaviour.
Try to use something like this:
int i = 1;
QFile outFile("path/to/file/out.txt");
outFile.open(QIODevice::ReadWrite);
QTextStream out(&outFile);
while (i < rows * 2)
{
QLineEdit* lineEdit = dynamic_cast<QLineEdit *>(this->getItem(i));
if (lineEdit)
{
QByteArray str = lineEdit->text().toLocal8Bit();
std::cout << str.data() << std::endl;
out << str.data() << "\n";
i += 2;
}
else
{
std::cerr << "Item at " << i << " is no QLineEdit*" << std::endl;
}
}
out.close();
Also please check whether QFile is actually open and whether QTextStream reports some errors when writing.

Segmentation fault with a element of QList

In my application I have a list of pointer to QFile objects:
QList<QFile*> files
This function adds the elements on the list:
void MumuServer::openFiles(){
QDir fileDir(QDir::toNativeSeparators(homeApp.path() + "/file"));
std::cout << fileDir.path().toStdString() << std::endl;
if(fileDir.exists()){ // there is files directory in the application home dir
std::cout << "fileDir exists" << std::endl;
QStringList filesList = fileDir.entryList();
for(int index = 0; index < filesList.size(); index++){
QString fileName = filesList.at(index);
if(this->blackListFile.contains(fileName)){
continue;
}
QString path = fileDir.path() + "/" + fileName;
std::cout << path.toStdString() << std::endl;
QFile file(QDir::toNativeSeparators(path));
if(file.exists()){
files.append(&file);
}
}
std::cout << this->files.size() << " files found" << std::endl;
}
After this function the QFile pointers are added on the QList. But, when I try to manipulate something on a element of the list getting it with the function at(int) a segmentation fault occurs.
Example:
QFile * file = files.at(index);
std::cout << "File size = " << file->fileName() << std::endl;
Somebody are seeing what am I doing wrong?
The objects that you put into your 'files' list have gone out of scope and were destroyed. Use the 'new' operator to allocate them instead. Be sure to delete them when you are done or you will have a memory leak.
QFile* file = new QFile(QDir::toNativeSeparators(path));
if(file->exists()){
files.append(file);
}

c++ private member variable unknown in another function

I have a newbie question about how to assign class member (setter). I am used to scripting and mostly there it's done via (in python)
def set_mymember(mymember):
self.mymeber = mymember
My coworker told me "self" and "this" are not needed in C++ , "this" exists and it's not wrong in this context but that would be hard to understand for me so he said I should not care. So I first tried according to his advice:
My class definition: - (it should create a sql query string)
class Query
{
public:
Query() { }
~Query() { }
void setoptions( std::string qtext_where="", bool qtext_erl=true, std::vector<std::string> kids=std::vector<std::string>() );
Query build_query( );
void set_db_table( std::string db_table );
void set_db_key( std::string db_key );
void set_m_qtext( std::string m_qtext );
void set_foo( std::string foo );
std::string sql();
std::string get_sql_update();
private:
std::string m_db_table; // Tabellenname
std::string m_db_key; // Tabellen-key
std::string m_qtext_where; // add.optionale where clause
std::string m_qtext; // fertiger SELECT
std::string m_sql_update; // fertiger UPDATE
bool m_erl; // nur erledigte waehlen?
std::vector<std::string> m_kids; // Liste von keys zu selecten
};
ANd here's one of the setter methods: I call them with filled string and vector, double check it in this code
void Query::setoptions( string qtext_where, bool erl, vector<string> kids ) {
m_qtext_where = qtext_where;
m_erl = erl;
m_kids = kids;
}
But when my app later calls query.build_query()
the variables are empty
Query Query::build_query( ) {
cout << "kids size" << m_kids.size() << endl;
cout << "m_qtext_where " << m_qtext_where << endl;
// Query zur auswahl der zu uebertragenden Datensaetze
string sql_update = "UPDATE " + m_db_table;
string qtext = "SELECT * FROM " + m_db_table;
string qtext_order = " ORDER BY " + m_db_key;
(...)
EDIT: So here's part of the app code which calls 1.setoptions, and 2.build_query
// read file line by line into vector of strings
vector<string> text_file;
ifstream ifs( input );
string temp;
while( getline( ifs, temp ) ) {
if (temp.substr(0,1) == "#" ) {
cout << "COMMENT: " << temp << endl;
continue;
}
cout << temp << endl;
text_file.push_back( temp );
}
// check: yes, vector has a size = number of lines
cout << "text_file size " << text_file.size() << endl;
// create Query object
Query query = Query();
// set the members, bool erl = true
query.setoptions( "", erl, text_file );
// call 2nd method
q2 = query.build_query();
Can't really tell whats going on without the full code, but I suspect that you're returning a query object from query.build_query that isn't a full copy of the query object, if that makes sense? Can you include the full text of build_query?
Also, I'd make the build_query method void, and not try to assign a fresh Query object back to a second Query object (q2) at all (unless you really need to, again, can't really tell without the full code), something like this:
void Query::build_query( ) {
std::cout << "kids size" << m_kids.size() << std::endl;
std::cout << "m_qtext_where " << m_qtext_where << std::endl;
}
main
{
...
Query query = Query();
// set the members, bool erl = true
query.setoptions( "", true, text_file );
// call 2nd method
query.build_query();
}
Also, just being pedantic here, but given that you're providing default args for all the options, I'd be inclined to initialise them in the constructor like this:
Query::Query()
: m_qtext_where("")
, qtext_erl(true)
, kids (std::vector<std::string>()
{}
And then instead of a setOptions method, have setters for each individual variable:
void setWhere(std::string qtext_where) {m_qtext_where = qtext_where ;}
void setErl(bool query_erl) { m_erl = query_erl; }
void setKids(std::vector<std::string> kids) { m_kids = kids; }
which you call only when you need to..