Segmentation fault using strcat - c

Here is my code :
char *name, name_log="log-";
------getting 'name' from user-----
strcat(name_log, name);
char ext[] = ".log";
strcat(name_log, ext);
What i need to end up with is name_log = "log-'name'.log" but Im getting a segmentation fault error :((. What am I doing wrong and how can I fix it ? Thx

For a start, if this is your code:
char *name, name_log="log-";
then name_log is a char, not a char pointer.
Assuming that's a typo, you cannot append to string literals like that. Modifications to string literals are undefined behaviour.
For a variable sized string, as user appears to be, probably the safest option is to allocate another string large enough to hold the result, something like:
char *name, *name_log = "log-", *ext = ".log";
// Do something to allocate and populate name
char *buffer = malloc (strlen (name_log) + strlen (name) + strlen (ext) + 1);
if (buffer == NULL) {
// Out of memory.
} else {
strcpy (buffer, name_log);
strcat (buffer, name);
strcat (buffer, ext);
// Do something with buffer.
free (buffer);
}
The malloc ensures you have enough space to do all the string operations safely, enough characters for the three components plus a null terminator.

string literals get allocated a fixed amount of memory, generally in a read only section, you instead need to use a buffer.
char buffer[64] = "log-";
strncat(buffer,".log",32);
On a side note, strcat is generally unsafe, you need to use something that that checks the size of the buffer it uses or with limits on what it can concatenate, like strncat.

A completely different solution would be this:
const char *prefix = "log-";
const char *suffix = ".log";
// There's a "char *name" somewhere
int size_needed;
char *result;
size_needed = snprintf(NULL, 0, "%s%s%s", prefix, name, suffix);
result = malloc(size_needed + 1);
snprintf(result, size_needed + 1, "%s%s%s", prefix, name, suffix);
// "result" now contains the desired string.
The nice thing about snprintf is that it returns the number of characters it would write if there was enough space. This can be used by measuring upfront how much memory to allocate which makes complicated and error-prone calculations unnecessary.
If you happen to be on a system with asprintf, it's even easier:
char *result = NULL /* in case asprintf fails */;
asprintf(&result, "log-%s.log", name);
// "result" must be released with "free"

you need to allcocate memory. You cannot add to a string in this way as the string added goes to memory which hasnt been allocated.
you can do
char[20] strarray;
strcat(strarray, "log-");
strcat(strarray, "abcd");

the name_log is pointed at a static place: "log-", which means is could not be modified, while as the first parameter in strcat(), it must be modifiable.
try changing name_log's type char* into char[], e.g.
char[20] name_log = "log-";

Related

Why is this use of strcpy considered bad?

I've spotted the following piece of C code, marked as BAD (aka buffer overflow bad).
The problem is I don't quite get why? The input string length is captured before the allocation etc.
char *my_strdup(const char *s)
{
size_t len = strlen(s) + 1;
char *c = malloc(len);
if (c) {
strcpy(c, s); // BAD
}
return c;
}
Update from comments:
the 'BAD' marker is not precise, the code is not bad, not efficient yes, risky (below) yes,
why risky? +1 after the strlen() call is required to safely allocate the space on heap that also will keep the string terminator ('\0')
There is no bug in your sample function.
However, to make it obvious to future readers (both human and mechanical) that there is no bug, you should replace the strcpy call with a memcpy:
char *my_strdup(const char *s)
{
size_t len = strlen(s) + 1;
char *c = malloc(len);
if (c) {
memcpy(c, s, len);
}
return c;
}
Either way, len bytes are allocated and len bytes are copied, but with memcpy that fact stands out much more clearly to the reader.
There's no problem with this code.
While it's possible that strcpy can cause undefined behavior if the destination buffer isn't large enough to hold the string in question, the buffer is allocated to be the correct size. This means there is no risk of overrunning the buffer.
You may see some guides recommend using strncpy instead, which allows you to specify the maximum number of characters to copy, but this has its own problems. If the source string is too long, only the specified number of characters will be copied, however this also means that the string isn't null terminated which requires the user to do so manually. For example:
char src[] = "test data";
char dest[5];
strncpy(dest, src, sizeof dest); // dest holds "test " with no null terminator
dest[sizeof(dest) - 1] = 0; // manually null terminate, dest holds "test"
I tend towards the use of strcpy if I know the source string will fit, otherwise I'll use strncpy and manually null-terminate.
I cannot see any problem with the code when it comes to the use of strcpy
But you should be aware that it requires s to be a valid C string. That is a reasonable requirement, but it should be specified.
If you want, you could put in a simple check for NULL, but I would say that it's ok to do without it. If you're about to make a copy of a "string" pointed to by a null pointer, then you probably should check either the argument or the result. But if you want, just add this as the first line:
if(!s) return NULL;
But as I said, it does not add much. It just makes it possible to change
if(!str) {
// Handle error
} else {
new_str = my_strdup(str);
}
to:
new_str = my_strdup(str);
if(!new_str) {
// Handle error
}
Not really a huge gain

How to fix gibberish printed after use strtok

I have uni project, I need to check if the syntax is right. I get pointer to a string, and check if the first token acceptable. In case it's OK, i move forward. But in case it's not OK, i need to print what is wrong.
What i did is to create a buffer since i can't change the original string.
After that i use strtok to cut the buffer, and look if the token i got is acceptable.
char *str = "sz = 12345";
printf("The check of MACRO: %d\n", isMacro(str));
int isMacro(char *str)
{
char buf = NULL;
char *token;
strcpy(&buf,str);
token = strtok(&buf," ");
printf("You here, value token is %s\n",token);
}
I expected that printf would print the 'sz' but it prints:
You here, value str is sz<▒R
char buf = NULL;
This is a type error. buf is a single character, but NULL is a pointer value. You can't store a pointer in a char.
strcpy(&buf,str);
This code has undefined behavior (unless str happens to be an empty string). buf is not a buffer, it is a single char, so it does not have room to store a whole string.
If you want to make a copy of a string, you need to allocate enough memory for all of its characters:
You could use strdup (which is in POSIX, but not standard C):
char *buf = strdup(str);
if (!buf) {
... handle error ...
}
...
free(buf);
You could replicate strdup manually:
char *buf = malloc(strlen(str) + 1);
if (!buf) {
... handle error ...
}
strcpy(buf, str);
...
free(buf);
You could use a variable-length array (but you're limited by the size of your stack and you have no way to check for errors):
char buf[strlen(str) + 1];
strcpy(buf, str);
...
buf is a single char instead of a pointer to a char. In fact, if you're planning to do strcpy to copy a string to it, you need to allocate memory first using malloc. Instead I'd suggest you to use a function like strdup instead of strcpy to create a copy of the original string to modify it using strtok. Remember to free the strduped string later.
Something like this.
int isMacro(char *str)
{
char *buf = NULL;
char *token;
buf = strdup(str);
token = strtok(buf," ");
printf("You here, value of token is %s\n",token);
free(buf);
}

C - create a string "from" struct parameter

Have a
typedef struct person {
char name[20]
char surname[20]
} person_t;
I need to create a string like XXXXXX:YYYYYY with the function like
char* personToString(person_t *p). I tried to make it:
char* personToString(person_t* p) {
int n1,n2;
n1=strlen(p->name);
n2=strlen(p->surname);
char *p = (char*) malloc((n1+n2+2)*sizeof(char));
strcat(p,puser->name);
strcat(p,":");
strcat(p,puser->surname);
return p;
}
This give me a reasonable output but I have some errors testing with valgrind! I also think that there is a way more classy to write the function!
When you malloc memory for p the memory will hold garbage values. Strcat will append a string after the null character, but in an uninitialized string will hold random values.
Replace the first strcat with strcpy.
You need to
strcpy(p,puser->name);
not
strcat(p,puser->name);
malloc does not initialize the buffer to zero, so strcat is searching for a null byte in p first and probably not finding one, reading past the end of the buffer and thus crashing.
Instead of one strcpy plus two strcat you can also write one call to sprintf:
sprintf(p, "%s:%s", puser->name, puser->surname);
First you should call string copy, then strcat:
strcat(p,puser->name);
should be:
strcpy(p,puser->name);
because memory allocated with malloc function keeps values garbage, by doing strcat for first you are concatenating after garbage -- it also brings Undefined behaviour in your code.
You can use void* calloc (size_t num, size_t size); instead of malloc(), calloc function initialized allocated memory with 0 (then strcat() no problem).
Also dynamically allocated memory you should deallocate memory block using void free (void* ptr);) explicitly.
This looks good to me,
char* personToString( struct person_t *p )
{
int len = strlen(p->name) + strlen(p->surname) + 2; // holds ':' + NULL
char *str = malloc( len ); // Never cast malloc's return value in C
// Check str for NULL
if( str == NULL )
{
// we are out of memory
// handle errors
return NULL;
}
snprintf( str, len, "%s:%s", p->name, p->surname);
return str;
}
NOTE:
Never cast malloc's return value in C.
Use snprintf when multiple strcat is needed, its elegant.
free the return value str here in caller.
Fixed struct and char variables.

Sprintf Segmentation Fault

numCheck is number between 1-1000. This code gives me a segfault only when I collect the results of sprintf in charcheck. If I simply use sprintf without using the results, I don't get a seg fault. What's happening here?
char * numString;
int charcheck = sprintf(numString, "%d", numCheck);
You need to provide your own memory for sprintf. Also, don't use sprintf, but rather snprintf:
char buf[1000] = {0};
snprintf(buf, 999, ....);
Alternatively you can allocate memory dynamically:
char * buf = new char[BUFSIZE];
snprintf(buf, BUFSIZE-1, ...);
/* ... */
delete[] buf;
The pointer given as the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string.
In this case you didn't initialize numString to point to some memory you allocated for the formatted string. Since numString isn't initialized it might point anywhere, and in your case trying to write the formatted output to that location results in a segmentation fault.
The first argument to sprintf must point to a valid buffer. You have a char* but it points to garbage.
Change your code to:
char numString[80] = { };
int charcheck = sprintf(numString, "%d", numCheck);
So that numString actually points to a valid buffer (of 80 characters in this example, all elements of which are initialised to 0).
It would also be good to use snprintf so you can pass the size of your buffer to it, which will help prevent buffer overflows:
const int bufsize = 80;
char numString[bufsize] = { };
int charcheck = snprintf(numString, bufsize - 1, "%d", numCheck);
Notice that you subtract one from the buffer size that you pass to snprintf because you don't want it to use the very last slot, which you want to make sure is NULL to denote the end of the string.
You need to allocate space for the result such as
char numString[50];
int charcheck = sprintf(numString, "%d", numCheck);
In your case the interal workings of sprintf are trying to reference NULL which is the default value for a pointer in your case.
The most straightforward thing to do is to use an array as above, e.g.,
char numString[80] = { };
suggested by Seth, Jesus and Kerrek.
I think the last answer from sth is a good explanation: "the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string." So apart from using an array of characters, which would force the allocation of memory for the string, you can also use this:
char *numstring = (char*) malloc(80);
This should let you explicitly free the allocated memory when it is no longer needed.

Typecast:LPCTSTR to Char * for string concatenate operation

Can u Give solution for this code of typecasting, LPCTSTR(here lpsubkey) to Char*
for below code snippet ,
char* s="HKEY_CURRENT_USER\\";
strcat(s,(char*)lpSubKey);
printf("%S",s);
here it makes error of access violation ,so what will be the solution for that?.
...thanks in advance
There are several issues with your code that might well lead to the access violation. I don't think any have anything to do with the cast you mentioned.
You are assigning a pointer to the first element of a fixed size char array to a char * and then attempt to append to this using strcat. This is wrong as there is no additional space left in the implicitly allocated string array. You will need to allocate a buffer big enough to hold the resulting string and then copy the string constant in there before calling strcat. For example, like so:
char *s = (char*)malloc(1024 * sizeof(char));
strcpy(s, "HKEY_CURRENT_USER\\");
strcat(s, T2A(lpSubKey));
printf("%s", s);
free(s);
Please note that the fixed size array I'm allocating above is bad practise. In production code you should always determine the correct size of the array on the go to prevent buffer overflows or use functions like strncat and strncpy to ensure that you are not copying more data into the buffer than the buffer can hold.
These are not the same thing. What are you trying to do?
The problem is you are trying to append to a string that you have not reserved memory for.
Try:
char s[1024] = "HKEY_CURRENT_USER";
strcat(s,(char*)lpSubKey );
printf("%S",s);
Do be careful with the arbitrary size of 1024. If you expect your keys to be much longer your program will crash.
Also, look at strcat_s.
ATL and MFC has set of macros to such conversion, where used next letters:
W - wide unicode string
T - generic character string
A - ANSI character string
OLE - BSTR string,
so in your case you need T2A macros
strcat does not attempt to make room for the combination. You are overwriting memory that isn't part of the string. Off the top of my head:
char *strcat_with_alloc(char *s1, char *s2)
{
if (!s1 || !s2) return NULL;
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
char *dest = (char *)malloc(len1 + len2 + 1);
if (!dest) return NULL;
strcpy(dest, s1);
strcat(dest, s2);
return dest;
}
now try:
char* s="HKEY_CURRENT_USER\\";
char *fullKey = strcat_with_alloc(s,(char*)lpSubKey);
if (!fullKey)
printf("error no memory");
else {
printf("%S",fullKey);
free(fullKey);
}

Resources