Temporary in a function call: UB? [duplicate] - c++

This question already has answers here:
is there issue will stringstream.str().c_str()? [duplicate]
(3 answers)
Closed 6 years ago.
Consider the following code, based on this answer:
#include <iostream>
#include <sstream>
class StringBuilder {
public:
template <typename T> inline StringBuilder &operator<<(T const &t) {
ss << t;
return *this;
}
inline char const * c_str() {
return ss.str().c_str();
}
private:
std::stringstream ss;
};
void foo(const char *x) {
std::cout << x << std::endl;
}
int main() {
foo((StringBuilder() << "testing " << 12 << 3 << 4).c_str());
return 0;
}
Does calling foo() with the temporary StringBuilder's return value cause UB in any way?
The reason I'm asking is that the example above works great, but in real life I'm using a library that, amongst other things, contains logging facilities, and using this library I'll get incorrect output (the logging function takes my char* correctly but overwrites it internally, which caused me to believe that the memory is no longer valid).

Yes, but not because of what you perhaps think.
The temporary StringBuilder in the function call is not destroyed until after foo returns, so that's fine.
However, the c_str() method returns the result of calling .str().c_str(), and the temporary string returned by this str() is destroyed as StringBuilder::c_str() returns, which means that the pointer returned is invalid outside. Using this pointer causes UB.

Related

Why does the pointer exist even after the unique_ptr to which the pointer is assigned goes out of scope? [duplicate]

This question already has answers here:
Dereferencing deleted pointers always result in an Access Violation?
(6 answers)
Why is the phrase: "undefined behavior means the compiler can do anything it wants" true?
(2 answers)
Pointers in c++ after delete
(3 answers)
Why does calling method through null pointer "work" in C++? [duplicate]
(4 answers)
Closed 6 months ago.
I recently started learning about smart pointers and move semantics in C++. But I can't figure out why this code works. I have such code:
#include <iostream>
#include <memory>
using namespace std;
class Test
{
public:
Test()
{
cout << "Object created" << endl;
}
void testMethod()
{
cout << "Object existing" << endl;
}
~Test()
{
cout << "Object destroyed" << endl;
}
};
int main(int argc, char *argv[])
{
Test* testPtr = new Test{};
{
unique_ptr<Test> testSmartPtr(testPtr);
}
testPtr->testMethod();
return 0;
}
My output is:
Object created
Object destroyed
Object existing
Why does row testPtr->testMethod() work? Doesn't unique_ptr delete the pointer assigned to it on destruction if the pointer is an lvalue?
Edit: I learned from the comments that this method doesn't check if the pointer exists. If so, is there a way to check if the pointer is valid?
Edit: I learned that I shouldn't do anything with invalid pointers. Thank you for all your answers and comments.
Edit: Even this code works:
#include <iostream>
#include <memory>
using namespace std;
class Test
{
public:
Test(int num) :
number{ num }
{
cout << "Object created" << endl;
}
void testMethod(int valueToAdd)
{
number += valueToAdd;
cout << "Object current value: " << number << endl;
}
~Test()
{
cout << "Object destroyed" << endl;
}
private:
int number;
};
int main(int argc, char *argv[])
{
Test* testPtr = new Test(42);
{
unique_ptr<Test> testSmartPtr(testPtr);
}
testPtr->testMethod(3);
return 0;
}
I think it's because the compiler optimized it. Anyway, I really shouldn't do anything with invalid pointers.
You do not need a std::unique_ptr to write code with the same issue
int main(int argc, char *argv[])
{
Test* testPtr = new Test{};
delete testPtr;
testPtr->testMethod(); // UNDEFINED !!!
return 0;
}
The output is the same as yours here https://godbolt.org/z/8bocKGj1M, but it could be something else entirely. The code has undefined behavior. You shall not dereference an invalid pointer.
If you had actually used members of the object in testMethod() some faulty output or a crash is more likely, but also not guaranteed. Looking ok is the worst incarnation of undefined behavior.
Your code demonstrates nicely why you should ban raw new completely. At least you should call new only as parameter to the smart pointers constructor, or even better, use std::make_unique. Its basically just a wrapper around a constructor call via new and its main purpose is to let you write code that is free of new:
int main(int argc, char *argv[])
{
auto testPtr = std::make_unique<Test>();
testPtr->testMethod();
return 0;
}
Even then you can access the raw pointer and do wrong stuff. Smart pointers help with ownership, but they are not fool-proof.

Why does dereferencing NULL work with cout << g_System->FileSystem()->GetFileData("test.txt"); in this example? [duplicate]

This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
Closed 2 years ago.
FileSystem() always returns NULL yet I can still call the functions of EngineFile through g_System->FileSystem()->;
I've tested this on VS2017 and one online compiler.
Obviously my intention is not to actually leave FileSystem() returning NULL because it was intended that Systems.ef get set to the EngineFile pointer. In a project I'm working on I accidentally forgot to ever set the pointer and when stepping through some other code I realized it was just returning NULL and it was still working.
I have condensed it down to a single file so all the code is right there.
Why does this work and how?
#include <iostream>
using namespace std;
class EngineFile
{
public:
EngineFile();
~EngineFile();
const char* GetFileData(const char* filename);
void ModifyBool(void);
private:
bool testmodify = false;
};
EngineFile::EngineFile()
{
}
EngineFile::~EngineFile()
{
}
void EngineFile::ModifyBool(void)
{
testmodify = true;
}
const char* EngineFile::GetFileData(const char* filename)
{
// open file filename
// stub function basically
return "This is the file data\n";
}
class Systems
{
public:
Systems();
~Systems();
EngineFile* const FileSystem(void);
private:
EngineFile* ef = NULL;
};
Systems::Systems()
{
}
Systems::~Systems()
{
}
static Systems* g_System;
EngineFile* const Systems::FileSystem(void)
{
return ef;
}
int main()
{
EngineFile* ef = new EngineFile();
g_System = new Systems();
// calling the function directly works as we would think
cout<<ef->GetFileData("test.txt");
// calling it through indirection with FileSystem returning NULL works
// why does this work? I feel like it should not work
cout << g_System->FileSystem()->GetFileData("test.txt");
// this will return null to show FileSystem returns null
EngineFile* efnulltest = g_System->FileSystem();
if (efnulltest == NULL)
cout << "efnulltest is NULL\n";
cout << "some extra text to show previous statement is still working\n";
// segfault as expected
g_System->FileSystem()->ModifyBool();
return 0;
}
It works because GetFileData does not reference any class data. The function is being called, and a (hidden) null ptr is passed at the 'this' parameter. Since 'this' is not used by the function, it works just as if it was a static function.

Confusing behavior of C++ string returns and c_str() casts [duplicate]

This question already has answers here:
Why does calling std::string.c_str() on a function that returns a string not work?
(3 answers)
Closed 2 years ago.
I am new to C++ programming (work with Java mostly), and this behavior of C++ classes, member strings and string conversions to const char* with c_str() is confusing me.
I have a header, a class and main function as follows:
sample.h
class Sample
{
private:
int id;
std::string text;
public:
Sample(int id);
void setId(int id);
int getId();
void setText(std::string txt);
std::string getText();
void loadText();
~Sample();
}
sample.cpp
Sample::Sample(int id)
{
this->id = id;
}
void Sample::setId(int id)
{
this->id = id;
}
int Sample::getId()
{
return this->id;
}
void Sample::setText(std::string txt)
{
this->text = txt;
}
std::string Sample::getText()
{
return this->text;
}
void Sample::loadText()
{
this->text = "Loaded";
}
Sample::~Sample()
{
std::cout << "Destructor is called." << std::endl;
}
main.cpp
void main()
{
int id = 1;
Sample* sample = new Sample(id);
// Case: 1 - If I do this, it does not work. Prints gibberish.
sample->loadText();
const char* text = sample->getText().c_str();
std::cout << text << std::endl;
// Case: 2 - Otherwise, this works.
sample->loadText();
std::cout << sample->getText().c_str() << std::endl;
// Case: 3 - Or, this works
sample->loadText();
std::string txtCpy = sample->getText();
const char* text = textCpy.c_str();
std::cout << text << std::endl;
}
All three cases are done one at a time.
Case 3 does satisfy my use case (which is, passing the string to a C library that expects a const char*. But, I can't figure out the difference between Case: 1 and Case: 3? If we are returning the string by value, how does copying it to an intermediate variable make it kosher for the run-time?
The result of c_str() is only valid while the string you called it on still exists. In case 3, txtCpy still exists at the point you are writing cout << text. But in Case 1, the string was the return value of sample->getText which is temporary and stop existing at the end of that line .
This issue always will exist if you take pointers or references to other objects. A naked pointer or reference has its own lifetime which may differ from the lifetime of the targeted object. This is unlike Java where object references all participate in the lifetime of the object.
As such, you always need to think about object lifetimes when using these features, and it's commonly recommended to instead use higher level features or other code styles that do not permit lifetime management errors.
You could consider adding a member function to Sample which gets a const char * pointing at the original string (although this is a wee violation of encapsulation, and still has a similar class of problem if you hold onto the pointer and then modify the underlying string). Better would be to just avoid working with the naked pointers entirely.
In this code snippet
const char* text = sample->getText().c_str();
std::cout << text << std::endl;
the variable text is assigned by a pointer (c_str()) of a temporary object returned from the member function getText. After this statement the temporary object will nit be alive, So the variable text has an invalid pointer,
The code snippet could be valid if the member function returned reference to the data member text like for example
const std::string & Sample::getText() const
{
return this->text;
}
Pay attention to that this declaration of main
void main()
is not a standard declaration.
The standard declaration of main without parameters is
int main()

returning reference to temporary object [duplicate]

This question already has answers here:
Will a reference bound to a function parameter prolong the lifetime of that temporary?
(4 answers)
const reference to a temporary object becomes broken after function scope (life time)
(2 answers)
Closed 4 years ago.
I was watching a video Curiously Recurring C++ Bugs at Facebook
at 14:58 at the code (see in the example I give here) he says that is is hopelessly broken. The reason is that returning reference to a temporary object should not work.
so why it works?
#include <iostream>
#include <map>
using namespace std;
const string& get_default(
const map<string,string>& map,
const string& key,
const string& dflt) {
auto pos = map.find(key);
return (pos != map.end() ?
pos->second : dflt);
}
int main()
{
map<string,string> m;
auto& value = get_default(m,"whatever","this is the default value");
cout << value << endl;
return 0;
}
I understand why I cannot return reference to a local variable (and that fails nicely when I try to print it), but I cannot make this code fail, and I dont know why.
I checked google and found that if temporary object is assigned to a reference the temporary objects lifetime will be extended (thats why it is working?).
If so why is this code so hopelessy broken?
Using: gcc 7.3.0, c++14
using the comments now I can see how to make it fail:
Thanks everyone :)
int main()
{
map<string,string> m;
auto& value = get_default(m,"whatever","this is the default value"); // const string& value = fails the same way
string a = "some long string";
cout << value << endl;//"some long string" will be printed here (this is how it fails - and shows that it is a mess)
return 0;
}
The life time of a temporary object is extended only in some contexts. The example in the posted code is not one of those contexts.
int foo() { return 10; }
...
int const& x = foo(); // Life of the temporary is extended.
However,
const int& foo() { return 10; } // Life of the temporary is not extended.
...
int const& x = foo(); // Dangling reference.
Your posted code is analogous to
const int& foo(int const& in) { return in; }
...
int const& x = foo(10);
Here, the reference is valid only inside foo. Once foo returns, the object is not alive any longer, and the reference becomes a dangling reference.

C++ - Can the following code cause undefined behavior? [duplicate]

This question already has answers here:
Calling a function pointer whose assigned function has less arguments then the pointer type
(2 answers)
Closed 7 years ago.
take a look at the following example:
#include <iostream>
#include <string.h>
void Func1(int x)
{
std::cout << "I'm function 1: " << x << std::endl;
}
void Func2(int x, const char* str)
{
std::cout << "I'm function 2: (this is arg1: " << x << " - args2: " << str << ")" << std::endl;
}
uintptr_t GetProcAddress(const char* _str)
{
if (strcmp(_str, "func1") == 0)
{
return reinterpret_cast<uintptr_t>(Func1);
}
else
{
return reinterpret_cast<uintptr_t>(Func2);
}
}
int main()
{
typedef void(*PROCADDR)(int, const char*);
PROCADDR ext_addr = nullptr;
ext_addr = (PROCADDR)GetProcAddress((const char*)"func1");
//call the function
ext_addr(10, "arg");
std::cin.get();
return 0;
}
We are basically calling Func1 with 2 arguments and can switch to call Func2 with the same args and everything works as intended.
Of course the address of both the arguments are always pushed on to the stack even though the second one is never used by the function itself.
Now I understand that the above code should never be used in production-code but my main question is, can the above code cause UB or is the code always expected to act like that?
Best regards
xx
Yes, it's undefined behavior. From [expr.reinterpret.cast]:
A function pointer can be explicitly converted to a function pointer of a different type. The effect of calling
a function through a pointer to a function type (8.3.5) that is not the same as the type used in the definition of the function is undefined.