I've been scratching my hair out but can't seem to find what is wrong with the following code. Here is the small snippet of valgrind output that it generates
Invalid read of size 1 at 0x4c22d82: strlen (mc_replace_strmem.c:242)
by 0x5E65CA: Application::readConfigurationFile() (char_traits.h:262)
by 0x5694BD: main Address 0xafc9660 is 24 bytes inside a block of size
39 free'd at 0x4C20E0D: operator delete(void*)
(vg_replace_malloc.c:342) by 0x635618:
Configurator::getParameterValue(char const*, char**) by 0x5E65B2:
Application:readConfigurationFile() (Application.cpp:77) by 0x5694BD:
main
bool Configurator::getParameterValue(const char *p_pParameterName, char** p_pParameterValue)
{
bool blReturnValue = false;
QDomElement element;
QDomNode node;
QDomNodeList list;
list = doc.elementsByTagName(p_pParameterName);
if (!list.isEmpty())
{
node = list.item(0);
element = node.toElement();
QString qs = element.text().toUtf8();
*p_pParameterValue = (char *)(qs.toStdString().c_str());
blReturnValue = true;
}
else
{
char sMessage[200];
sprintf(sMessage, "<Configurator::getParameterValue> Error! Parameter %s could not be found\n", p_pParameterName);
m_outputFunction(sMessage);
}
return blReturnValue;
}
bool Configurator::parseFile()
{
bool blReturnValue = false;
QString errorStr;
int errorLine;
int errorColumn;
if (!doc.setContent((QIODevice*)(&file), true, &errorStr, &errorLine, &errorColumn))
{
char aTemp[512];
sprintf(aTemp, "<Configurator::parseFile> error! can not read the file row: %d, column: %d:\n",errorLine, errorColumn);
m_outputFunction(aTemp);
}
else
{
closeFile();
blReturnValue = true;
}
return blReturnValue;
}
bool Application::readConfigurationFile()
{
bool blReturnValue = false;
m_outputFunction("<Application::readConfigurationFile> Reading configuration..\n");
if(m_configurator.parseFile())
{
blReturnValue = true;
m_configurator.writeParameters();
char *pTemp = 0;
if(!m_configurator.getParameterValue("center_no", m_bCenterNo))
m_bCenterNo = 1;
if(m_configurator.getParameterValue("highway_header", &pTemp))
m_strHighwayHeader.assign(pTemp);
else
m_strHighwayHeader.assign("... HIGHWAY"); // Default value
}
return blReturnValue;
}
Can somebody please tell me why I see invalid reads, I don't even use malloc/calloc in this code snippet.
*p_pParameterValue = (char *)(qs.toStdString().c_str());
Why you did so? QString is local variable and toStdString return new std::string
std::string QString::toStdString () const
So, returned std::string will be deleted. c_str() returns pointer to const char*. Quote from n3337 draft:
const charT* c_str() const noexcept;
const charT* data() const noexcept;
1 Returns: A pointer p such that p + i == &operator[](i) for
each i in [0,size()]. 2 Complexity: constant time. 3 Requires: The
program shall not alter any of the values stored in the character
array.
if(m_configurator.getParameterValue("highway_header", &pTemp))
m_strHighwayHeader.assign(pTemp);
Wrong. Since value in pTemp was deleted, when temporary object qs.toStdString() was deleted.
You are in effect returning a pointer to a local variable. In getParameterValue the variable qs is local inside a block, and you assign that strings pointer to p_pParameterValue. When getParameterValue the stack space formerly occupied by qs is now reclaimed and the pointer pTemp now points to unused memory. This is undefined behavior, and can cause lots of bad stuff to happen.
The temporary string object returned from qs.toStdString() allocates memory for the string, which is freed when the temporary is destroyed (after evaluation of the full expression). If you are compiling with optimization, it is likely that the std::string d'tor is inlined into your function, so it doesn't show up in your call stack.
When you want to continue using the string data after the function is done, you need to make it persist. The (in my opinion) sanest way is to return a std::string object rather than a char *, so the last parameter could be a std::string ** (which is filled by new std::string(qs.toStdString())), or a std::string & which is assigned to.
If you have the Boost libraries, you can also use boost::optional<std::string> as the return type, which provides a "string with a valid flag" data type.
Related
With regard to this line:
The s[9] that goes through void setChar(size_t index, char c), but what is *this (inside the if, in the line: ``)?
Is it s1 or nullptr? Then what is _str (in the same line: *this = _str;), is it s1?
class MyString {
size_t _size = 0;
char* _str = nullptr;
int* _pRefCount = nullptr;
}
operator char() const {
return ((const MyString&)_s)[_index];
}
};
void detach() {
if(_pRefCount && --*_pRefCount == 0) {
delete []_str;
delete _pRefCount;
}
}
void attach(const MyString& str) {
_size = str._size;
_str = str._str;
_pRefCount = str._pRefCount;
++*_pRefCount;
As always *this is the object the function is executed for. If you are inside s1[4] the *this would be s1.
Using *this = _str; is just an involved way of calling one of the operator= overloads for MyString. It has the effect of "unsharing" by assigning a new copy of _str to itself.
Also, it has been known for quite some time that reference counted strings is not an optimization. For example in the output of s1[0] the code will create an unnecessary CharProxy just in case someone would assign a value to it. You also get a separate memory allocation for the refcount of each string you create, even if you never intend to share it
I write a simple string class in cpp, but when I add some new features something bad happened. The stack overflow when to call the object s3 destructor. So I spent an hour to fix it, but I did not find something wrong with my code locially and the grammer is correct. So I ask my friend to recode it to help me to fix it, but when he recoded it on his Mac. There was no bad thing happened in his program. So I am REALLY REALLY confused about it and need help to fix it, if there is something wrong with my codes in truth. If not, maybe I should comment on issue Visual Studio 2015. :(
This is MySTLString.h
class MySTLString
{
public:
// Default constructor
MySTLString();
// Constructs the string with count copies of character ch.
MySTLString(size_t count, char ch);
// Convert char consequence to MySTLString
MySTLString(const char *s);
// Copy constructor
MySTLString(const MySTLString &s);
// Destructor
~MySTLString();
using size_type = size_t;
using CharT = char; // the character type
using value_type = char; // the value_type
using reference = value_type; // reference
using const_reference = const value_type&; // const reference
// Returns reference to the character at specified location pos.
reference at(size_type pos);
// const_reference at(size_type pos) const; // I do not know how to convert a reference to const_reference when to return
// Returns reference to the first character
CharT& front();
const CharT& front() const;
// Returns reference to the last character, equivalent to operator[](size() - 1)
CharT& back();
const CharT& back() const;
// Returns pointer to the underlying array serving as character storage.
CharT* data();
const CharT* data() const;
// Operator assignment overloaded
MySTLString& operator=(const MySTLString &s);
// Operator [] overloaded
reference operator[](size_type pos);
const_reference operator[](size_type pos) const;
private:
char* data_;
int length_;
};
This is MySTLString.cpp
#include "MySTLString.h"
#include <cstring>
#include <iostream>
#include <stdexcept>
// Construct a empty string(zero size and unspecified capacity).
MySTLString::MySTLString():data_(nullptr), length_(0)
{
}
// Constructs the string with count copies of character ch.
MySTLString::MySTLString(size_t count, char ch)
{
length_ = count;
if (count == 0)
{
data_ = nullptr;
return;
}
else // when count is not 0
{
data_ = new char[length_];
for (size_t i = 0; i < count; ++i)
{
data_[i] = ch;
}
}
}
// Constructs the string with contents initialized
// with a copy of the null-terminated character string pointed to by s.
// The length of the string is determined by the first null character.
MySTLString::MySTLString(const char *s)
{
length_ = strlen(s);
if (length_ == 0)
{
data_ = nullptr;
return;
}
data_ = new char[length_];
strcpy(data_, s);
}
// Copy constructor.
// Constructs the string with the copy of the contents of other.
MySTLString::MySTLString(const MySTLString &s)
{
if (s.data_ == nullptr)
{
length_ = 0;
data_ = nullptr;
}
else
{
length_ = strlen(s.data_);
data_ = new char[length_];
strcpy(data_, s.data_);
}
}
// Destructor
// Free data_ pointer memory
MySTLString::~MySTLString()
{
if (data_ != nullptr)
{
delete []data_;
}
std::cout << "length_ = " << length_ << std::endl; // for test
}
// Returns a reference to the character at specified location pos.
// Bounds checking is performed, exception of type std::out_of_range will be thrown on invalid acess
MySTLString::reference MySTLString::at(size_type pos)
{
if (pos >= strlen(data_))
{
throw std::out_of_range("pos is cross-border!\n");
}
return data_[pos];
}
// Returns reference to the first character
MySTLString::CharT& MySTLString::front()
{
if (data_ == nullptr)
{
throw std::out_of_range("String is empty!\n");
}
return data_[0];
}
const MySTLString::CharT& MySTLString::front() const
{
return this->front();
}
// Returns reference to the last character
MySTLString::CharT& MySTLString::back()
{
if (data_ == nullptr)
{
throw std::out_of_range("String is empty!\n");
}
return data_[0];
}
const MySTLString::CharT& MySTLString::back() const
{
return this->back();
}
// Returns pointer to the underlying array serving as character storage.
// The pointer is such that the range[data(); data()+strlen(data_)] is valid
// in it correspond to the values stored in the string
MySTLString::CharT* MySTLString::data()
{
if (data_ == nullptr)
{
throw std::out_of_range("String is empty!\n");
}
return data_;
}
const MySTLString::CharT* MySTLString::data() const
{
return this->data();
}
// Operator= overloaded
// Replace the contents with a copy of str.
// If *this and str are the same object, this function has no effect
MySTLString& MySTLString::operator=(const MySTLString &s)
{
// If *this and str are the same object, this function return *this
if (this == &s)
{
return *this;
}
if (s.length_ == 0)
{
length_ = 0;
data_ = nullptr;
return *this;
}
char* temp = s.data_; // copy *s.data_
delete data_; // free old memory
data_ = new char[s.length_]; // copy data to data_ member
strcpy(data_, temp);
length_ = s.length_;
return *this; // return this object
}
// Operator[] overloaded
// Returns a reference to the character at specified location pos.
// No bounds checking is perfromed.
MySTLString::reference MySTLString::operator[](size_type pos)
{
return this->at(pos);
}
MySTLString::const_reference MySTLString::operator[](size_type pos) const
{
return this->operator[](pos);
}
This is TestMySTLString.cpp(PS: I have delete other normal functions)
#include "MySTLString.h"
#include <iostream>
using std::cout;
using std::endl;
int main(void)
{
// test constructor that convert char consequence to MySTLString
MySTLString s3("qwe");
return 0;
}
This is the pic when to call the destructor
This is the pic of stack information when to call the destructor
const MySTLString::CharT& MySTLString::front() const
{
return this->front();
}
will result in infinite recursion, causing stack overflow. If you want to re-use implementaion of the non-const version, you will have to use:
const MySTLString::CharT& MySTLString::front() const
{
return const_cast<MySTLString*>(this)->front();
}
Make the same change to MySTLString::back() and MySTLString::data().
While you do have infinite recursive calls (as explained in those other answers) it isn't an answer to the question you are asking. The error you are getting is a heap corruption bug.
The debug CRT of Visual Studio allocates guard bytes to the left and right of heap-allocated memory, and fills them with specific byte patters. When the memory gets deleted, those guard bytes are compared against the byte pattern. If they do not match, you get to see the heap corruption dialog, because you wrote outside the allocated memory.
The bug is not in your d'tor. The d'tor is just the place, where the heap corruption is detected, because it releases the heap-allocated memory.
There are several bugs with the same pattern in your code: strlen returns the number of characters not including the zero terminator. When you strcpy into the allocated array, the zero terminator gets written just outside the allocated memory.
You need to change the following code
MySTLString::MySTLString(const char *s)
{
length_ = strlen(s);
if (length_ == 0)
{
data_ = nullptr;
return;
}
data_ = new char[length_];
strcpy(data_, s);
}
to
MySTLString::MySTLString(const char *s)
{
length_ = strlen(s);
if (length_ == 0)
{
data_ = nullptr;
return;
}
data_ = new char[length_ + 1]; // Allocate enough memory to account for zero terminator
strcpy(data_, s);
}
Make sure to update the other occurrences, where you call strlen accordingly.
Other random notes:
You don't need to check for nullptr before calling delete[]. While not harmful, it's not required either. Simply use delete[] data_; in your d'tor.
There were no error reports for your friend, because they were presumably using XCode. XCode will not report heap corruption errors, unless it is specifically set up to do so (the tedious process is explained at Enabling the Malloc Debugging Features). And even then it's mostly useless.
Have a look in your visual Studio 2015 Build output. Mine says
data': recursive on all control paths, function will cause runtime stack overflow
back': recursive on all control paths, function will cause runtime stack overflow
front': recursive on all control paths, function will cause runtime stack overflow
operator[]': recursive on all control paths, function will cause runtime stack overflow
I have a class String with the following members:
Class String{
...
private:
char* word
int length
}
String's copy assignment returns a String& and allocates word on the heap.
I also have a linked list class written in C that has a function:
void *popFront(struct List *list)
{
struct Node prevHead = list->head
list->head = prevHead->next;
void *info = prevHead->info;
free(prevHead);
return info;
}
My task is to write the same function for a C++ linked list that uses the C function. This is what I have:
String List::popFront()
{
String s = (*(String *) ::popFront(&list));//casting the void * to String
return s;
}
The C++ method should return the object by value. That's what I thought the method would do. However,
I'm getting memory leaks. Any hint on how I need to modify List::popFront() so that it returns by value? Thanks.
First store the returned pointer locally as a pointer to string, then make a local copy of the string, then delete the object, the pointer points to and finally return the local copy.
EDIT:
Btw. you can use c++11's smart pointers to avoid the extra copy:
String List::popFront()
{
auto s = std::unique_ptr<String>((String*) ::popFront(&list));
return *s;
}
but that is probably not, what your teacher aims at.
popFront removes the element from the linked list and frees the node, but not the info portion. This is the responsibility of the caller of popFront, e.g.
String *s = (String *) ::popFront(&list);
delete s;
But you must also keep a copy, which you can return from the method
String List::popFront()
{
String *s = (String *) ::popFront(&list);
String tmp = *s;
delete s;
return tmp;
}
You declare String List::popFront() which returns an object, not a pointer. And String s = ... declares an object, not a pointer or reference. So assigning s a value constructs a new object s being a copy of what ::popFront returned, then a next copy of s is returned and s itself gets destroyed. However the object unlinked by ::popFront() remains on a heap, making a leak.
Don't create an intermediate copy of String object, return the pointer to unlinked object, so that a caller can link it to its own list or delete it after use:
String *List::popFront()
{
String *s = (String *) ::popFront(&list);//casting the void * to String *
return s;
}
I'm new to c++ and am still struggling with the whole pointer thing.
Let's say I have a function that returns a char* pointing to the start of an array of characters / a string.
char* read() {
char data[] = "this for example";
return *data;
}
then later I want to access this data, but I don't think I can do something like this:
char* data = read();
if(data[3] == 's')
return true;
what is the right way to use the data returned by read() in this example?
In this case it is better to use standard class std::string
std::string read()
{
char data[] = "this for example";
return data;
}
//...
std::string data = read();
if( data[3] == s )
return true;
As for your code snippet then if to rewrite it without errors it would have undefined behaviour because you return a pointer to a local array that will be destroyed after exiting the function.
In your read() function, return *data; returns a char not a char*. Also stack memory is not supposed to be accessed after your function returns. Make it static. It should be:
char* read()
{
static char data[] = "this for example";
return data;
}
You can't return pointer to an automatic variable. It invokes undefined behavior. Allocate data dynamically.
char *data = new char[20];
Do not forget to delete the allocated memory when you are done by using
delete[] data;
Better to use std::vector or std::string instead.
I'm having trouble passing data by reference to a given method - when the method access the data, it's corrupted, but I'm sure that when the method is called it's not (by debuggin). Here is something like the code:
//Calling code
const void* tempPointer = array.mid(readerPos,RE8K_ICDEF_HARMONICS_SIZE).constData();
const re8k_ics_harmonics* const newStruct = static_cast< const re8k_ics_harmonics* >(tempPointer);
DSInstance().updateHarmonics(*newStruct);
//method
void DataStream::updateHarmonics(const re8k_ics_harmonics &infoHarmonics, ...)
{
//Use infoHarmonics
}
So if I use the debugger and go put a breakpoint in the "calling code" in the last line and watch what is in newStruct, I see that the data is perfect as it should be. Than the method is called and I put a new breakpoint (or go "next line") till enter the first line inside updateHarmonics, and when I see the content of infoHarmonics, I see part of the data corrupted and part of it is there.
Why is the code becoming corrupted? What should I do? :x
Additional info:
array is a Qt's QByteArray
readerPos is a int that iterates over the QByteArray from the point data should be read
constData() returns a const char*
Thanks,
Momergil
QByteArray QByteArray::mid (int pos, int len = -1 ) const
This function returns object by value, so in the line
const void* tempPointer = array.mid(readerPos,
RE8K_ICDEF_HARMONICS_SIZE).constData();
you are taking a pointer to temporary data. This pointer is not valid just in the next line. You should create object on the heap or use stack allocated instance, e.g:
QByteArray midQ = array.mid(readerPos, RE8K_ICDEF_HARMONICS_SIZE);
const void* tempPointer = midQ.constData(); // pointer valid as long
// as midQ breaths
const re8k_ics_harmonics* const newStruct =
static_cast< const re8k_ics_harmonics* >(tempPointer);
DSInstance().updateHarmonics(*newStruct);