Segmentation Fault in vsprintf() - c++

#define printm(p) writeToAnalyticsFile p
void writeToAnalyticsFile (const char* format, ...)
{
std::string errorLog;
std::string headerLine = "\"errorText\":";
FILE *fp = fopen( "Analyse.txt", "w" );
if( 0 == fp )
{
}
else
{
va_list args;
va_start (args, format);
vsprintf (const_cast<char*>(errorLog.c_str()),format, args);
va_end (args);
fputs(headerLine.c_str(),fp);
fputs("\"",fp);
fputs( errorLog.c_str(), fp );
fputs("\"",fp);
fclose(fp);
}
}
class abc
{
public:
static const char * func()
{
std::string str = "john";
return str.c_str();
}
};
int main()
{
printm(("My Name is %s and surname is %s and age is %d",abc::func(),"john",25));
return 0;
}
I basically want to replace printm((--- )) with writeToAnalytics(--) which writes data to file.
I am getting Segmentation Fault with below code.
Problem is with calling abc::func() in main. Is it because of local storage of str in func()?

The func function is incorrect, as it is returning an invalid pointer:
static const char * func()
{
std::string str = "john";
return str.c_str();
}
The string is destroyed at the end of the function, and therefore the pointer str.c_str() is a dangling pointer - pointing to a string that doesn't exist any more.
Solution is to just return "john". Literals last forever.
static const char * func()
{
return "john";
}
Or, better still, just return the string,
static string func()
{
std::string str = "john";
return str;
}
and use abc::func().c_str() at the call site.
(There may be other problems, but this is the most obvious to me)

Related

Why does my char* copier return different things?

Writing a simple string copier and testing it in the main() fucntion. What's odd is that sometimes the program returns
"HelloHello"
like it should, but maybe every third time I run it, the program prints out:
"Hello!Hello!▌▌▌▌▌▌▌▌▌▌▒"UòB╚"
Why is the tail of garbage data only sometimes being added to the end of my second string?
#include <iostream>
using namespace std;
int strlength(const char* c)
{
int size = 0;
while (*c) {
++c;
++size;
}
return size;
}
char* mystrdup(const char* c)
{
int size = strlength(c);
char* result = new char;
copy(c, c + size, result);
return result;
}
void print_array(const char* c)
{
int size = strlength(c);
while (*c) {
cout << *c;
++c;
}
}
int main()
{
char test[] = "Hello!";
char* res = mystrdup(test);
print_array(test);
print_array(res);
}
The program has undefined behavior because you are allocating not enough memory for the result string.
char* mystrdup(const char* c)
{
int size = strlength(c);
char* result = new char;
^^^^^^^^^^^^^^^^^^^^^^^
copy(c, c + size, result);
return result;
}
Moreover you are not copying the terminating zero to the result string.
At least the two functions strlength and mystrdup can look the following way
size_t strlength( const char *s )
{
size_t size = 0;
while ( s[size] ) ++size;
return size;
}
char * mystrdup( const char *s )
{
size_t size = strlength( s ) + 1;
char *result = new char[size];
copy( s, s + size, result );
return result;
}
Of course instead of the standard algorithm std::copy you could use the standard C function strcpy declared in the header <cstring>.
strcpy( result, s );
And do not forget to delete the allocated array.
char* res = mystrdup(test);
//…
delete [] res;
Pay attention to that the function print_array does not use the variable size. There is no need to output a C-string character by character.
The function could be defined like
std::ostream & print_array( const char *s, std::ostream &os = std::cout )
{
return os << s;
}
And at last the identifier c is usually used with single objects of the type char. If you deal with a string then it is better to use the identifier s.
You have multiple bugs in your code. You allocate wrong memory (char instead of char array). You don't delete the memory. Stop using C-string and use std::string
#include <iostream>
#include <string>
using std::cout;
void print_array(const char* c)
{
while (*c) {
cout << *c;
++c;
}
}
int main()
{
std::string = "Hello!";
std::string res = test;
print_array(test.c_str());
print_array(res.c_str());
}
In strcpy you need to create a char size.
char* mystrdup(const char* c)
{
int size = strlength(c);
char* result = new char[size];
copy(c, c + size, result);
return result;
}

How to define a function to return a pointer to a "" value when no matching data is found?

I want my function() to always return a "" string under error conditions else return a string that is converted to string from an unsigned long integer variable.
My initial implementation is as follows:
uint32 cfgVariable_1 = 4;
uint32 cfgVariable_2 = 1;
const char* getCfgVariable (const char* msg)
{
char* retValue = "";
if(strcmp("cfgVariable_1", msg)==0)
{
// Since I want my function to return a const char* and returning uint32_t is not an option
sprintf((retValue), "%lu", cfgVariable_1);
return (const char*)retValue;
}
else if(strcmp("cfgVariable_2", msg)==0)
{
// Since I want my function to return a const char* and returning uint32_t is not an option
sprintf((retValue), "%lu", cfgVariable_2);
return (const char*)retValue;
}
else
{
//error
}
return (const char*) retValue;
}
When the function is called at different instances to get the cfgVariables, I expect my function getCfgVariable() to return "" on error condition, when no match found.
Somewhere in code:
const char* CfgValue = NULL;
CfgValue = getCfgVariable("cfgVariable_1");
Here CfgValue gets pointed to location which contains 4
later
const char* CfgValue = NULL;
CfgValue = getCfgVariable("cfgVariable_3");
I expect to get a "" back but I get 4 instead (CfgValue gets the same address as before).
Fix implemented by me works, but I fail to understand the logic behind it, fix:
const char* getCfgVariable (const char* msg)
{
const char* defValue = "";
char* retValue = "\0";
if(strcmp("cfgVariable_1", msg)==0)
{
// Since I want my function to return a const char* and returning uint32_t is not an option
sprintf((retValue), "%lu", cfgVariable_1);
return (const char*)retValue;
}
else if(strcmp("cfgVariable_2", msg)==0)
{
// Since I want my function to return a const char* and returning uint32_t is not an option
sprintf((retValue), "%lu", cfgVariable_2);
return (const char*)retValue;
}
else
{
//error
}
return defValue;
}
I see during debugging that defValue and retValue get pointed to two different locations that do not get overwritten. defValue always gets pointed to the same address when its initialized with "" and retValue gets pointed to a different address when initialized with "\0". Can anyone explain the logic behind this ? Is there a better implementation for my use case ?
My Solution after considering the comments:
const char* getCfgVariable (const char* msg)
{
const char* retValue = "";
std::ostringstream oss;
if(!strcmp("cfgVariable_1", msg))
{
oss << cfgVariable_1;
}
else if(!strcmp("cfgVariable_2", msg))
{
oss << cfgVariable_2;
}
else
{
//error
return retValue;
}
const std::string tmp = oss.str();
retValue = tmp.c_str();
return retValue;
}
Thanks for the comments so far and this solution is still open to further improvement suggestions.
Constexpr strings such as "\0", "", "cfgVariable_1", etc. These are constant strings in memory compiled into your resulting executable. Attempting to write values into those strings is downright dangerous! In old style C, you'd have to use malloc to allocate a bit of memory to use for your string. This is a real pain to deal with in practice (and not ideal for someone who's learning C++).
A far simpler solution is to start using the C++ string object, std::string (which handles all of the dynamic memory allocation for you!). This should reduce your problem to something a little simpler (and most importantly, safer!):
#include <string>
#include <sstream>
std::string getCfgVariable (const char* const msg)
{
std::ostringstream oss;
if(!strcmp("cfgVariable_1", msg))
{
oss << cfgVariable_1;
}
else
if(!strcmp("cfgVariable_2", msg))
{
oss << cfgVariable_2;
}
return oss.str();
}
Doing this in C, you have 2 choices. Allocate the memory for the returned string, or use a static buffer that is always available (which is what this example does).
uint32 cfgVariable_1 = 4;
uint32 cfgVariable_2 = 1;
const char* getCfgVariable (const char* msg)
{
static char retValue[32] = {0};
if(strcmp("cfgVariable_1", msg)==0)
{
// Since I want my function to return a const char* and returning uint32_t is not an option
sprintf(retValue, "%lu", cfgVariable_1);
return retValue;
}
else if(strcmp("cfgVariable_2", msg)==0)
{
// Since I want my function to return a const char* and returning uint32_t is not an option
sprintf(retValue, "%lu", cfgVariable_2);
return retValue;
}
else
{
//error
}
return retValue;
}
However, because now the retValue is an array fixed in memory, the string returned would only be valid until the next call to getCfgVariable, which could be a little strange....
const char* A = getCfgVariable("cfgVariable_1");
printf("%s\n", A); // prints '4'
const char* B = getCfgVariable("cfgVariable_2");
printf("%s\n", B); // prints '1'
printf("%s\n", A); // now this will print '1', and not '4'.
const char* C = getCfgVariable("anythingElse");
printf("%s\n", C); // prints ""
printf("%s\n", B); // prints ""
printf("%s\n", A); // aso prints ""

C++ function returning string gives garbage in the text of the string

So I have a function returning a std::string as follows:
string ReadShaderSource(const char* filename, GLint& shaderSize) // Load the shader source code.
{
ifstream::pos_type size;
string text;
ifstream file(filename, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
shaderSize = (GLuint)size;
text.resize(size);
file.seekg(0, ios::beg);
file.read(&text[0], text.size());
file.close();
return text;
}
else
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error!",
"Could not load the shader source code from the file.", NULL);
Lunar::Exit();
}
return "";
}
But When I call the function like this:
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
The value of testStr is full of this:
0x036fdcd8
"îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþ...
Which makes no sense. The function returns the right value, so when I return text in the function it contains the source code of the shader, but when I do
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
testStr is full of rubbish.
Any ideas?
Thank you!
You need to use
string str = ReadShaderSource("test.glsl", size);
const char* testStr = str.c_str();
instead of
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
When you use the second form, you are storing a pointer in testStr that is not valid any more since the returned value of the function is a temporary string.
As was pointed out by #IInspectable, you could also use a const& to extend the lifetime of the temporary object.
string const& str = ReadShaderSource("test.glsl", size);
const char* testStr = str.c_str();
The following program is well behaved:
#include <iostream>
#include <string>
std::string foo()
{
return "This is a test.";
}
void bar(std::string const& str)
{
std::cout << str.c_str() << std::endl;
}
int main()
{
std::string const& str = foo();
bar(str);
std::cout << str.c_str() << std::endl;
}
Re
“when I do const char* testStr = ReadShaderSource("test.glsl", size).c_str(); testStr is full of rubbish.”
you're initializing the pointer to point to a buffer in a temporary string, that has ceased to exist already when the initialization finishes.
Instead use a string for the result variable.
Note that the conclusion that the function returns garbage is unwarranted, it does not follow from that observation of garbage, but might still be true.
You should test anew, with proper result variable type, to check that.

Issue with returning a heap char pointer from a function

This code works:
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
if ( str == NULL )
{
char* buf = new char[2];
sprintf_s(buf, 2, "%s", "");
return buf;
}
else
return _com_util::ConvertBSTRToString(*str);
}
But I am trying to avoid multiple returns, bad programming I have been told. However it just wont work:
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
// char* result = new char[1]; (attempt #1, produces garbage as output)
char* result = (char*) malloc(1 *sizeof(char)); (attempt #2, more garbage as output)
if ( str == NULL )
{
char* buf = new char[2];
sprintf_s(buf, 2, "%s", "");
result = buf;
}
else
result = _com_util::ConvertBSTRToString((BSTR) str);
return result;
}
There is an article about returning the string as a char** in argument (by ref), but I don't understand why a char* from the heap cannot be returned ?
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
char* ret;
if ( str == NULL )
{
ret = new char[1];
ret[0] = 0;
}
else
ret = _com_util::ConvertBSTRToString(*str);
return ret;
}
And btw, you should not mix C++ new with C malloc.
Also, it is arguable that multiple return points is a bad practice. There are many situations when the code is more readable when you have multiple return points.
You'd do this:
char* CFichierTrace::ConvertBSTRToString(BSTR* str)
{
char* buf;
if ( str == NULL )
{
buf = new char[2];
sprintf_s(buf, 2, "%s", "");
}
else
buf = _com_util::ConvertBSTRToString(*str);
return buf;
}
I just suppose you know why you pass a pointer to a BSTR, instead of a BSTR.
char* CFichierTrace::ConvertBSTRToString(BSTR* str) {
return _com_util::ConvertBSTRToString(*str);
}
Due to BSTR-semantics, this is the proper implementation.
To clarify, all proper BSTR-functions treat NULL identical to a 0-length BSTR.
Anyway, use multiple return points wherever they make sense, unless you have a broken coding-standard disallowing such.

How to prevent invalid/corrupted string assignment

I have written a function to process a variadic input arguments like below -
std::string ReturnMessage(const char * format, ...)
{
va_list vl;
va_start(vl, format);
std::stringstream ss;
for(int i = 0; format[i] != '\0'; ++i)
{
switch(format[i])
{
case 's':
{
char *str = NULL;
str = va_arg(vl, char *);
if(*str)
{ //Getting memory access violation here
ss << str;
}
}
break;
}
}
val_end(vl);
return ss.str()
}
No when user assigns non string value(ReturnMessage("%s %s","Testing",100)) as string and at that str gets assigned to Bad Pointer and if(*str) statement throws Access Violation exception which is valid here. But How can I prevent invalid string to get added into stringstream??