So I have this code:
void blocks(std::string URL, std::string auth)
{
const char* cstr_url = URL.c_str();
std::string s = ("Authorization: " + auth);
const char* auth_header = s.c_str();
(··· and so on ···)
}
And everything seems fine if we look in the "autos" field in Debug mode:
But if we try to change the code in a way that ("Authorization: " + auth) is a temporary instance of the String class, in order to avoid declaring the s variable (and therefore saving space -at least, that's my purpose-):
void blocks(std::string URL, std::string auth)
{
const char* cstr_url = URL.c_str();
const char* auth_header = ("Authorization: " + auth).c_str();
(··· and so on ···)
}
...what we get in the Debug "autos" field is something quite different (lots of Ý chars):
I thought C++ could support these kind of things (which I don't know how are they technically called, I assume "implicit instance" as an original name). I would swear Java could support these "implicit instances" though.
So the actual question is, what's happening in here? Is there any workaround to avoid declaring an s variable?
The debug build has very kindly thoroughly destroyed the chars that ceased to exist after that statement, rather than leaving them in a state where you might think things were ok.
The C++ name for such things is "rvalue" (and specifically "prvalue"), which denotes the value category of the expression ("Authorization: " + auth). Rvalues are objects that are about to be destroyed.
auth_header is now an invalid pointer, and doing anything with it (besides re-assigning it) has undefined behaviour.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
This is basically my main function :
void GameObject::deserialize(QList<GameObject*> *list)
{
QFile _file(_filename);
if (!_file.open(QIODevice::ReadOnly | QFile::Text))
{
qDebug() << "Couldn't open file to read";
return;
}
QTextStream in(&_file);
while (!in.atEnd())
{
QString currentline = in.readLine();
if (currentline.startsWith("GameObject {"))
{
list->append(getGameObject(&in, currentline));
}
}
_file.close();
}
It opens a file, and parses it for GameObjects.
The getGameObject (cleaned up) function is this one :
GameObject *GameObject::getGameObject(QTextStream *in, QString current_line)
{
GameObject *go = new GameObject();
QList<GameObjectVariable*> govl;
bool ok;
while (!in->atEnd() && !current_line.startsWith("} end GameObject"))
{
current_line = in->readLine();
if (current_line.startsWith("GameObjectVariable")) {
GameObjectVariable *gov = this->getGameObjectVariable(in, current_line);
govl.append(gov);
go->setVariableList(&govl);
qDebug() << QString("AR : Type As String of the returned object : ") + gov->getTypeAsAString();
qDebug() << QString("AR : Type as number : ") + QString::number(gov->getType());
if (gov->getType() == NUMBER_LIST) {
qDebug() << "Number List";
qDebug() << QString("Value as a string of the number list : ") + ((GameObjectVariableNumberList*)gov)->getValueAsAString();
}
else if (gov->getType() == STRING_LIST) {
qDebug() << "String List";
qDebug() << QString("Value as a string of the string list : ") + ((GameObjectVariableStringList*)gov)->getValueAsAString();
}
else if (gov->getType() == GAMEOBJECT) {
qDebug() << "GameOBject";
qDebug() << QString("Value as a string of the gameobject : ") + ((GameObjectVariableGameObject*)gov)->getValueAsAString();
}
}
}
return go;
}
This one basically is a big mess of ifs, but it works, up to a point. The goal of this function is to read line by line, and return a gameobject filled with the read info. This is a weird format we use for the project though.
The last bunch of lines are Debug lines I've put in to try to understand where the problem was.
This is the other (cleaned up) function that's related :
GameObjectVariable* GameObject::getGameObjectVariable(QTextStream *in, QString current_line)
{
GameObjectVariable *gov;
bool ok;
int type;
QList<QString> ls;
QList<int> ln;
QList<GameObject*> lgo;
while (!in->atEnd() && !current_line.startsWith("} end GameObjectVariable")) {
current_line = in->readLine();
if (current_line.startsWith("type: "))
{
type = current_line.right(current_line.size() - 5).toInt(&ok, 10);
}
else if (current_line.startsWith("value: ")) {
if (current_line.startsWith("value: {"))
{
while (!in->atEnd() && !current_line.startsWith("} end value"))
{
current_line = in->readLine();
if (!current_line.startsWith("} end value"))
{
if (type == GAMEOBJECT_LIST)
{
lgo.append(getGameObject(in, current_line));
}
else if (type == STRING_LIST)
{
ls.append(current_line);
}
else if (type == NUMBER_LIST)
{
ln.append(current_line.toInt(&ok, 10));
}
}
}
if (type == GAMEOBJECT_LIST)
((GameObjectVariableGameObjectList*) gov)->setValue(&lgo);
else if (type == STRING_LIST)
((GameObjectVariableStringList*) gov)->setValue(&ls);
else if (type == NUMBER_LIST)
((GameObjectVariableNumberList*) gov)->setValue(&ln);
}
}
}
qDebug() << QString("BR : Get the type as string : ") + gov->getTypeAsAString();
qDebug() << QString("BR : Get the type as number : ") + QString::number(gov->getType());
qDebug() << QString("BR : get the value as string of the object : ") + gov->getValueAsAString();
return gov;
}
This function reads the lines in the GameObjectVariable 'tag'. The type is a defined int that is macroed to the text type we use for the other if forest.
Now this again works fine, except for when we have a list of values (the part that starts with else if (current_line.startsWith("value: {"))).
The debug lines at the end of the function (the "BR :" ones) show the object properly filled, but the ones at the end of the getGameObject calling function (starting with "AR :") crash, because apparently the value is null.
GameObjectVariable object is this one (again, cleaned up) :
class GameObjectVariable
{
public:
GameObjectVariable(QString name, QList<int> idListEdit = QList<int>(), QList<int> idListView = QList<int>());
// GETTERS
QString getName() {return this->name;}
int getType() {return this->type;}
void *getValue() {return this->value;}
// SETTERS
void setName(QString name) {this->name = name;}
void setValue(void* value) {this->value = value;}
QString getTypeAsAString();
virtual QString getValueAsAString() = 0;
private:
QString name;
protected:
void *value;
int type;
};
getValueAsAString is set as virtual because every type mentioned in the code above (like GameObjectVariableStringList overwrite this one with a return of their value with the correct type)
Finally, here is an example of file we try to deserialize :
GameObject {
name: Number 1
type: Test
GameObjectVariableStringList: {
type: 3
name: List String
value: {
String 1
String 2
} end value
} end GameObjectVariable
(type: 3 corresponds to STRING_LIST)
The main problem is bolded.
The problem
getGameObjectVariable()'s local variable GameObjectVariable *gov is an uninitialised pointer, which you suddenly cast to some other type and then start trying to call methods on.
How did you expect that to end? You are telling the compiler this: Poke at random memory as if it holds an allocated, initialised object. Also, this object might have any of 3 different types.
Seriously: What did you think was happening in that function, that it was somehow producing a usable object? I'm genuinely curious.
Anyway, for at least three reasons, this is malformed code that exhibits completely undefined behaviour:
The pointer is uninitialised, so like any uninitialised variable, reading/dereferencing it is UB.
No object is alive at the (invalid) address to which it points, but you call methods on it as if an object lives there; that is UB.
Said methods then presumably start writing stuff to whatever arbitrary address you happened to end up at, with no permission, which is lethal UB.
(Also, even if there was valid memory to access and a valid object at it, casting the pointer to another type then using it is only valid if an instance of that other type was specifically allocated at that address - or some more-derived one, but then the C-style cast is (A) bad style and (B) potentially very dangerous if e.g. multiple and/or virtual inheritance are in play.)
Due to all this UB, anything can happen, or nothing might happen, or exactly what you want just might happen - but the code is fundamentally broken.
For example, as seems to have occurred here, the compiler might coincidentally act like there is a valid object while within the same function, but then you return that garbage pointer to getGameObject(), and it suddenly reveals that you fed it rubbish.
UB gives the compiler, and particularly its optimising layers, free reign to do whatever they want, chiefly because they are allowed to assume UB does not happen. So, e.g. they can assume there must be a valid object pointed to by gov, even if there blatantly isn't. That assumption gets lost after you return, though, for whatever reason.
Who knows? The precise reasons for the observed behaviour are pretty uninteresting to speculate about. You can produce assembly output if you really want to know why what happened happened.
The (immediate) solution
But the key point is this: You need to replace this particular mess with proper, valid code - and fast. So, you need to assign a valid value to the pointer, by assigning it the address of a newly allocated object of whichever type is required. Only then do you have an address to which you are allowed access, with a living object at it, of the right type. It's then OK to create a cast pointer of the real derived type to call derived methods, but return a pointer-to-base for others to use.
Conditionally calling methods, etc.
Also, those conditional casts and calls to setValue() look suspicious. Why not just make that a virtual method and let the compiler resolve the right variation? Generally, if you have some conditional construct deciding which method to call based on the real type... You should just use virtual functions. Most concern about their overhead is FUD, and most attempts to avoid that overhead are no more efficient to execute and much worse to read.
For instance, do you expect all users of any GameObjectVariable to repeat the same hoop-jumping exercise of checking what type it is and casting to the equivalent type of pointer to call the right (derived, hiding-not-overriding) version of setValue()? Hello, boilerplate spaghetti code, for no reason.
I think this points at more general bad patterns in your design. Rather than having huge functions that repeatedly have to check the type and do different things, with different lists depending on the type, etc. - why not simply check the type specified by the input line, and construct a new object of that type with, for example, the rest of the line as an argument, letting it create and populate whatever type of list and any other specific attributes it needs? Then you'll have tidy methods that do single things, not labyrinths that must constantly remind themselves what kind of object they're working with.
Avoid new
Note that I said said to assign the pointer from "a newly allocated object", not a newly allocated object... Most people should not ever need to use raw new or delete in C++, so you should return a unique_ptr, ideally from std::make_unique<Foo>(args).
There is a fair exception if, as hyde points out in the comments, your new object is of a type that should have its lifetime managed by a parent object to which it is then added. Then new is OK - assuming there's no better way to phrase it, like I dunno, make_floating_reference<Foo>(args). But, as hyde also said, that isn't the case for your GameObjectVariable, so a smart pointer is the way to go for that.
(Normally I would say you probably don't need dynamic allocation at all, but since you appear to need polymorphism and the objects clearly don't comprise a known set on the stack to which you could push non-owning pointers/reference-wrappers into the container, it seems that you do.)
In C++ is perfectly legitimate to do:
bool x = "hi";
Because "hi" is translated by compiler to a char array and returns a pointer to that array, which is a number and number can be implicitly converted to bool (0 is false, anything else is true).
So I have these ctor:
Exception(QString Text, bool __IsRecoverable = true);
Exception(QString Text, QString _Source, bool __IsRecoverable = true);
Sadly I figured out that calling
Exception *e = new Exception("error happened", "main.cpp #test");
It creates a new instance of "Exception" class which is created using Exception(QString Text, bool __IsRecoverable = true); constructor, which is wrong to a point.
Is there a simple way to ensure that correct function is called, other than restructuring the constructors entirely, changing position of arguments, etc?
Firstly, I'm not sure why you're dynamically allocating an exception class. I'm not sure that's ever a good idea.
You can explicitly construct a QString:
Exception e("error happened", QString("main.cpp #test"));
Or you can pass the third argument:
Exception e("error happened", "main.cpp #test", true);
Or you can add an additional constructor that takes const char* and will be preferred over the conversion to bool:
Exception(QString Text, const char* Source, bool IsRecoverable = true);
You can easily make this forward to the QString version. Also note that names beginning with an underscore and a capital letter or with two underscores are reserved.
My suggestion would be to not use default arguments. They contribute to overload resolution problems like this, and anyway it is not very readable to just see true as an argument. Whoever's reading the code then has to stop and go look up what the true means. Even if it's yourself you may forget it in a few months time when you come back to the code, especially if you do this sort of thing a lot.
For example:
struct Exception: public whatever
{
Exception(char const *text);
Exception(char const *text, char const *source);
};
struct RecoverableException: public Exception
{
RecoverableException(char const *text);
RecoverableException(char const *text, char const *source);
};
It's a little bit more typing in this source file but the payoff is that your code which actually uses the exceptions is simpler and clearer.
To implement these constructors you could have them all call a particular function in the .cpp file with relevant arguments selecting which behaviour you want.
I have a preference for using char const * rather than QString as I am paranoid about two things:
unwanted conversions
memory allocation failure
If constructing a QString throws then things go downhill fast. But you may choose to not worry about this possibility because if the system ran out of memory and your exception handling doesn't prepare for that possibility then it's going to terminate either way.
Details:
Im using this github project to convert a Json to an object.
https://github.com/ereilin/qt-json
With this json:
{
"bin": "/home/pablo/milaoserver/compile/Devices01.olk",
"temp":"/home/pablo/milaoserver/temporal/",
"port": "1234",
"name": "lekta",
}
with this two lines I create two char pointers:
char* bin = configuration["bin"].toString().toLatin1().data();
char* temp = configuration["temp"].toString().toLatin1().data();
Debugging the app I have the proper strings.
However when I use them, concretely the "bin" char changes to
`hom
Any Idea?
SOLUTION IN COMMENTS:
The problem was the "persistence" of the data.
I found the solution with:
std::string binAux(configuration["bin"].toString().toLatin1().data());
std::string tempAux(configuration["temp"].toString().toLatin1().data());
char* bin = new char[binAux.size()+1] ;
strcpy(bin, binAux.c_str());
char* temp = new char[tempAux.size()+1] ;
strcpy(temp, tempAux.c_str());
Your error here is because of temporary object.
toString() create a temporary object no longer available after the semicolon.
The standard state :
12.2 Temporary objects [class.temporary]
3/ [...] Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception. The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.
That is, when you want to access it you have Undefined Behavior.
This should solve your problem :
QString str = configuration["bin"].toString().toLatin1();
QByteArray ba = str1.toLatin1();
char *bin = ba.data();
But what do you want to use char* ? You are in C++, use std::string or Qstring instead :
#include <string>
std::string bin(configuration["bin"].toString().toLatin1().data());
Can you please try something like
std::string sbin(configuration["bin"].toString().toLatin1().data());
std::string sTemp(configuration["temp"].toString().toLatin1().data());
toString() creates a QString object that is deleted immediately, so the data that is contained in it will be freed. I do recommend you to store the data in a QString until you use that char* bin.
Your solution could be shorter, like this:
char* bin = strdup(configuration["bin"].toString().toLatin1().data().c_str());
char* temp = strdup(configuration["temp"].toString().toLatin1().data().c_str());
strdup() does virtually all you do.
I am working in C++ with two large pieces of code, one done in "C style" and one in "C++ style".
The C-type code has functions that return const char* and the C++ code has in numerous places things like
const char* somecstylefunction();
...
std::string imacppstring = somecstylefunction();
where it is constructing the string from a const char* returned by the C style code.
This worked until the C style code changed and started returning NULL pointers sometimes. This of course causes seg faults.
There is a lot of code around and so I would like to most parsimonious way fix to this problem. The expected behavior is that imacppstring would be the empty string in this case. Is there a nice, slick solution to this?
Update
The const char* returned by these functions are always pointers to static strings. They were used mostly to pass informative messages (destined for logging most likely) about any unexpected behavior in the function. It was decided that having these return NULL on "nothing to report" was nice, because then you could use the return value as a conditional, i.e.
if (somecstylefunction()) do_something;
whereas before the functions returned the static string "";
Whether this was a good idea, I'm not going to touch this code and it's not up to me anyway.
What I wanted to avoid was tracking down every string initialization to add a wrapper function.
Probably the best thing to do is to fix the C library functions to their pre-breaking change behavior. but maybe you don't have control over that library.
The second thing to consider is to change all the instances where you're depending on the C lib functions returning an empty string to use a wrapper function that'll 'fix up' the NULL pointers:
const char* nullToEmpty( char const* s)
{
return (s ? s : "");
}
So now
std::string imacppstring = somecstylefunction();
might look like:
std::string imacppstring( nullToEmpty( somecstylefunction());
If that's unacceptable (it might be a lot of busy work, but it should be a one-time mechanical change), you could implement a 'parallel' library that has the same names as the C lib you're currently using, with those functions simply calling the original C lib functions and fixing the NULL pointers as appropriate. You'd need to play some tricky games with headers, the linker, and/or C++ namespaces to get this to work, and this has a huge potential for causing confusion down the road, so I'd think hard before going down that road.
But something like the following might get you started:
// .h file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction();
}
// .cpp file for a C++ wrapper for the C Lib
namespace clib_fixer {
const char* somecstylefunction() {
const char* p = ::somecstylefunction();
return (p ? p : "");
}
}
Now you just have to add that header to the .cpp files that are currently calling calling the C lib functions (and probably remove the header for the C lib) and add a
using namespace clib_fixer;
to the .cpp file using those functions.
That might not be too bad. Maybe.
Well, without changing every place where a C++ std::string is initialized directly from a C function call (to add the null-pointer check), the only solution would be to prohibit your C functions from returning null pointers.
In GCC compiler, you can use a compiler extension "Conditionals with Omitted Operands" to create a wrapper macro for your C function
#define somecstylefunction() (somecstylefunction() ? : "")
but in general case I would advise against that.
I suppose you could just add a wrapper function which tests for NULL, and returns an empty std::string. But more importantly, why are your C functions now returning NULL? What does a NULL pointer indicate? If it indicates a serious error, you might want your wrapper function to throw an exception.
Or to be safe, you could just check for NULL, handle the NULL case, and only then construct an std::string.
const char* s = somecstylefunction();
if (!s) explode();
std::string str(s);
For a portable solution:
(a) define your own string type. The biggest part is a search and replace over the entire project - that can be simple if it's always std::string, or big one-time pain. (I'd make the sole requriement that it's Liskov-substitutable for a std::string, but also constructs an empty string from an null char *.
The easiest implementation is inheriting publicly from std::string. Even though that's frowned upon (for understandable reasons), it would be ok in this case, and also help with 3rd party libraries expecting a std::string, as well as debug tools. Alternatively, aggegate and forward - yuck.
(b) #define std::string to be your own string type. Risky, not recommended. I wouldn't do it unless I knew the codebases involved very well and saves you tons of work (and I'd add some disclaimers to protect the remains of my reputation ;))
(c) I've worked around a few such cases by re-#define'ing the offensive type to some utility class only for the purpose of the include (so the #define is much more limited in scope). However, I have no idea how to do that for a char *.
(d) Write an import wrapper. If the C library headers have a rather regular layout, and/or you know someone who has some experience parsing C++ code, you might be able to generate a "wrapper header".
(e) ask the library owner to make the "Null string" value configurable at least at compile time. (An acceptable request since switching to 0 can break compatibility as well in other scenarios) You might even offer to submit the change yourself if that's less work for you!
You could wrap all your calls to C-stlye functions in something like this...
std::string makeCppString(const char* cStr)
{
return cStr ? std::string(cStr) : std::string("");
}
Then wherever you have:
std::string imacppstring = somecstylefunction();
replace it with:
std::string imacppstring = makeCppString( somecystylefunction() );
Of course, this assumes that constructing an empty string is acceptable behavior when your function returns NULL.
I don't generally advocate subclassing standard containers, but in this case it might work.
class mystring : public std::string
{
// ... appropriate constructors are an exercise left to the reader
mystring & operator=(const char * right)
{
if (right == NULL)
{
clear();
}
else
{
std::string::operator=(right); // I think this works, didn't check it...
}
return *this;
}
};
Something like this should fix your problem.
const char *cString;
std::string imacppstring;
cString = somecstylefunction();
if (cString == NULL) {
imacppstring = "";
} else {
imacppstring = cString;
}
If you want, you could stick the error checking logic in its own function. You'd have to put this code block in fewer places, then.
I asked a similar question a couple of days ago, but I'm looking for more insight. I'm getting an AccessViolationException when I add a string to my program:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at _cexit()
at <CrtImplementationDetails>.LanguageSupport._UninitializeDefaultDomain(Void * cookie)
at <CrtImplementationDetails>.LanguageSupport.UninitializeDefaultDomain()
at <CrtImplementationDetails>.LanguageSupport.DomainUnload(Object source, EventArgs arguments)
at <CrtImplementationDetails>.ModuleUninitializer.SingletonDomainUnload(Object source, EventArgs arguments)
The program has a bunch of const std::string's at the top level:
const std::string caseDelimitedOption = "CaseDelimited";
const std::string endOfLineOption = "EndOfLine";
const std::string functionNameDelimitWordsOption = "FunctionNameDelimitWords";
const std::string functionNameStartCaseOption = "FunctionNameStartCase";
const std::string indentStringOption = "IndentString";
const std::string lowerCaseOption = "LowerCase";
const std::string newLineBetweenDoAndWhileOption = "NewLineBetweenDoAndWhile";
const std::string nextLineOption = "NextLine";
const std::string nextLineAsWellAsCloseParenOption = "NextLineAsWellAsCloseParen";
const std::string noBracesAroundSingleStatementBlockOption = "NoBracesAroundSingleStatementBlock";
const std::string openBraceLocationOption = "OpenBraceLocation";
const std::string underscoreDelimitedOption = "UnderscoreDelimited";
const std::string upperCaseOption = "UpperCase";
const std::string whiteSpaceBeforeLeadingCmntOption = "WhiteSpaceBeforeLeadingComment";
If I replace last string with:
const std::string whiteSpaceBeforeLeadingCmntOption = ""; //"WhiteSpaceBeforeLeadingComment";
then the exception goes away. Is this just extra memory (from the string) hitting some bad memory that was caused elsewhere in my program? Or is the exception related to the string?
Thanks for any help,
Joe
I assume these strings are global variables.
Are you trying to access these strings from the constructor of another global variable (or from some method that is called before main is entered)?
If this is the case you are suffering from the probelem that global variable initialization order is undefined across multiple compilation units. There are a few solutions but more information about your application would probably be useful.
First test to see if main is even entered.
I would think that it working with the empty string is the result of some compiler optimization trick.
Try
valgrind --leak-check=full your.exe
and remember to compile your application with -g to get source code line in the executable.
The problem isn't the string. Somewhere in your program, you're reading or writing out of bounds. This results in undefined behavior, meaning that the program might appear to run, you might get an access violation, or it might crash with another error, or... anything else might happen.
The reason the string appears to make a difference is simply that it changes the program subtly, causing the out-of-bounds access to reach an unallocated page.