Why do I get a segmentation fault when using strncpy? - c

I am getting segmentation fault when using strncpy and (pointer-to-struct)->(member) notation:
I have simplified my code. I initialise a struct and set all of it's tokens to an empty string. Then a declare a pointer to a struct and assign the address of the struct to it.
I pass the pointer to a function. I can print out the contents of the struct at the beginning of the function, but if I try to use the tp -> mnemonic in a strncpy function, I get seg fault. Can anyone tell me what I am doing wrong?
typedef struct tok {
char* label;
char* mnem;
char* operand;
}Tokens;
Tokens* tokenise(Tokens* tp, char* line) {
// This prints "load"
printf("Print this - %s\n", tp -> mnem);
// This function gives me segmentation fault
strncpy(tp -> mnem, line, 4);
return tp;
}
int main() {
char* line = "This is a line";
Tokens tokens;
tokens.label = "";
tokens.mnem = "load";
tokens.operand = "";
Tokens* tp = &tokens;
tp = tokenise(tp, line);
return 0;
}
I have used printf statements to confirm that the code definitely stops executing at the strncpy function.

The problem is that tp->mnem is pointing to a string literal, which is generally allocated in a read-only segment of memory. Therefore it's illegal to overwrite it. Most likely what you need to do instead is something like this:
Tokens tokens;
tokens.label = "";
tokens.mnem = strdup("load");
tokens.operand = "";
This will give you a dynamically allocated block of memory for mnem, which you can then write into as much as you like. Of course, you have a couple of other problems too: first, you'll need to remember to release that memory with free later; second, you'll have to be aware of the size of the buffer you've allocated so that you don't overwrite it.
If you know that the contents of mnem will never exceed 4 bytes, then you might instead change your structure declaration like so:
typedef struct tok {
char* label;
char mnem[5]; // note: +1 byte for a NULL terminator
char* operand;
}Tokens;
Then, you'd initialize it like this:
Tokens tokens;
tokens.label = "";
strcpy(tokens.mnem, "load");
tokens.operand = "";
This relieves you of the responsibility of managing the memory for mnem, although you still have some risk of overrunning your buffer.

Following line
tokens.mnem = "load"
assigns mnem to address of string literal, which is typically located in read-only data segment, so changing this memory with strncpy() or any other function will fail.

The problem is you've assigned string literals to the members of your Tokens structure and are trying to overwrite that memory (specifically, the mnem field) in tokenise.
Most modern OSes will allocate memory for string literals from a special read-only section of your program's address space. If you try to write to that memory, then your program will die with a segfault.
This is why the type of a string literal is const char *, not char *. Your compiler should warn you when you try to assign these to the fields of tokenise.
If you want to overwrite the memory later, you need to allocate the memory dynamically using malloc or change the members of the Tokens structure to fixed-length arrays, then copy the initial value into the allocated memory. Of course if you allocate the memory dynamically you need to free it later too.

You're calling strncpy() without having allocated the buffer spacem, just like Shadow said.
The literal string "load" you set the mnem member to in the initializer is not overwritable.
If you want to be able to change the string stored, and the size is reasonable, it might be easiest to just change the declaration of the struct field to char mnem[5];.
Also, please note that strncpy() has quite weird semantics. Check if you have strlcpy(); it's a better function.

You're getting a segmentation fault because this line:
strncpy(tp -> mnem, line, 4);
Is trying to copy four characters from 'line' into a location occupied by a string literal as assigned here:
tokens.mnem = "load";
The string literal is stored in a special text part of your program and may not be modified.
What you need to do is allocate a buffer of your own into which the string will be copied:
tokens.mnem = (char*) malloc (bufferSize);
And free the buffer when you are done using it.

This line is questionable:
strncpy(tp -> mnem, line, 4);
You are relying on a function that returns a pointer to memory that is not allocated. The return of *tokenise() is undefined. Its returning a pointer to memory that could contain all kinds of stuff, and that you don't have permission to modify.
It should return an allocated pointer.

You might malloc the tp variable. If you don't malloc there is no guarantee that the memory is actually yours. Don't forget to free the memory when you are finished.

Related

in c why the dereference of the s point to string value not working?

why when i use the program it return s = null
the get_string function can have update to make the program work
it is : string s = malloc(sizeof(string));
but in the end of the function and after return s; i cant free(s);
or before return s; i will lose the data i stored
i tried to search more about dereference pointers but i got nothing.
#include <stdio.h>
typedef char* string;
string get_string(string q)
{
string s = NULL;
printf("%s",q);
scanf("%s",s);
return s;
}
int main(void)
{
string a = get_string("name : ");
printf("name is %s\n",a);
}
Here are two correct uses of scanf to read a string:
char s1[10];
scanf("%9s", s1);
char *s2 = malloc(100);
scanf("%99s", s2);
Notice that in both cases — s1 and s2 — I had to explicitly say how much memory I wanted for my string. Then, when I called scanf, I included that information — 1 less than the overall string size — in the %s format, so that I could tell scanf not to read a bigger string than my string variable could hold.
Notice, by contrast, that in your get_string function, you did not allocate any memory to hold your string at all. Your variable s was a null pointer, explicitly pointing to no memory at all.
This is something that's very easy to overlook at first: Most of the time, C does not allocate memory for strings for you. Most of the time, this is your responsibility.
Now, an additional concern is that even when you do allocate memory for a string, you have to think about how long that memory will stick around, and whether anyone has to explicitly deallocate it. And there are some additional mistakes that are easy to make. In particular, suppose you took my first example (s1) to heart, and tried to fix your get_string function like this:
char *get_string(char *q)
{
char s[100]; /* WRONG */
printf("%s",q);
scanf("%99s",s);
return s;
}
Here you have given scanf a proper array to read in to, but it's local to the get_string function, meaning that it will disappear after get_string returns, and it will be useless to the caller.
Another possibility is
#include <stdlib.h>
char *get_string(char *q)
{
char s = malloc(100); /* better */
if(s == NULL) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
printf("%s",q);
scanf("%99s",s);
return s;
}
This will work just fine. Note that I have checked to see whether malloc succeeded. (If it fails, it returns a NULL pointer.) But now we have the issue that some memory has been allocated which might never be freed. That is, get_string returns a pointer to dynamically-allocated memory, and it's the caller's responsibility to free that memory when it's no longer needed. The caller doesn't have to, but if there end up being 1,000,000 calls to get_string, and if none of the allocated blocks ever gets freed, that's a lot of memory wasted.
First as other people have noted in the comments the Typedef in this case isn't very helpful as it hides the fact its a pointer. Also char* is vary commonly used and not a type complicated enough for a typedef IMO.
For your other issues the problem appears to be that you are thinking of the value as a C++ string instead of a char pointer. In C there aren't string objects but instead people use char* which can pointer blocks of chars and we determine the end of the string by putting a null character at the end of list of characters.
So the reason you can't print the NULL string is because it is undefined behavior to pass a NULL pointer to printf. When you change it to s = malloc(sizeof(string)); the pointer is no longer null but instead pointing to the start of a block of memory that is sizeof(string) bytes long. You should be doing malloc(sizeof(char)*strlen(q)); instead so you have a block of memory holding a string with the length of string q instead of just one character. More generally it would be malloc(sizeof(char)*NUM_CHARS);.
When it come to the free call. You can't call free(s) after return s; because no statements after return s; will occur because the function has returned and no longer executing. As for calling before, calling free(s) deallocates that block of memory that s is pointing too from the malloc(sizeof(string)) is pointing to. Here you have to remember that the function isn't returning the memory or the string but instead it returns the pointer to the string. So if you delete the memory the pointer is pointing to then you lose it once you return.

Understanding results with valgrind

For the following code I have the following defintion:
typedef struct string {char* data; int length;} string;
If I run the following code with valgrind, I got conditional jump or move depends on unitinialized value and seg. fault:
string* s = (string*) malloc(sizeof(string));
strcpy("Hello", s->data);
free(s);
First of all, I can't understand why I got above errors.
I thought if I add to that code free(s->data) it will freed memory but program will run ok.
How I think:
I know sizeof(string) equal to 4(pointer to char) + 4(int) = 8.
then we allocate 8 bits for s.
strcpy will copy the string into data but I got a problem here. why?
There are multiple problems:
string* s = (string*) malloc(sizeof(string));
which should better be
string* s = malloc(sizeof(*s));
allocates memory for s->data, but does not make s->data point to any valid memory location. If you want to make use of the memory location, you need to make sure that it points to a valid memory location. For example: you'd need to malloc() for s->data seperately.
That said, the syntax for strcpy() says, it's strcpy(dest, source), so in your case
strcpy("Hello", s->data);
attempts to
read from an unitilized memory location
write into a string literal
either of which invokes undefined behaviour.
You should write
strcpy(s->data, "Hello");
after ensuring s->data is a valid destination.

C segmentation fault using malloc'ed strings

Essentially, I have a structure for a linked list in my code,
struct node{
char* val;
struct node *next;
};
Then later I try to do some things to it...
...
addr = malloc(sizeof(struct node));
addr->val = malloc(72);
addr->val = "";
snprintf(addr->val, 1000, "%s", ident);
...
...
This gives me a segmentation fault at the snprintf. Valgrind says the following
Process terminating with default action of signal 11 (SIGSEGV)
==10724== Bad permissions for mapped region at address 0x40566B
==10724== at 0x4EB0A32: vsnprintf (vsnprintf.c:112)
==10724== by 0x4E8F931: snprintf (snprintf.c:33)
==10724== by 0x4016CC: id (Analyzer.c:267)
...
I am fairly new to C as opposed to C++, but I thought that calling malloc on the char* should make it valid, especially since I can initialize and print it, so I don't understand why the snprintf wouldn't work.
I also had my program print out the addresses of both variables, and the address valgrind complains about is indeed from addr->val.
I also tried using strcpy instead of snprintf but had the same result.
Thanks.
addr->val = malloc(72);
This line dynamically allocates 72 bytes and assigns the address of that memory region to addr->val.
addr->val = "";
This then sets addr->val to point to the address of a string constant, discarding the address of the malloced area of memory that it previously contained, causing a memory leak.
When you then try to use snprintf, you're attempting to write to a string literal. Since these are typically stored in a read-only section of memory, attempting to do so results in a core dump.
There's no need for addr->val = "";. It throws away allocated memory; it doesn't set that allocated memory to an empty string, which is probably what you thought it would do. Even if it did, it's useless anyway because snprintf will overwrite anything that might be there.
The code
addr->val = malloc(72);
addr->val = ""; <====
overwrites val pointer with "", address of a static area, made of 1 character (of value 0). Remove this line.
And
snprintf(addr->val, 1000, "%s", ident);
Accept a length of 1000 while you only allocated 72 characters.
snprintf(addr->val, 72, "%s", ident);
is better.
addr->val = malloc(72);
addr->val = "";
The second line re-assignes addr->val to an address in read-only section (where string literals lie), and discards the address of allocation from malloc, which can lead to a potential memory leak.
I know you want to clear it. To assign strings, you should use strcpy()
strcpy(addr->val, "");
But since you want to empty it, it's easiest to set the first character to zero:
addr->val[0] = '\0';
Besides, you're trying to do a potentially harmful job:
snprintf(addr->val, 1000, "%s", ident);
You intended to allocate 72 bytes, but why us the second parameter going up to 1k? Change it to a safer number:
snprintf(addr->val, 72, "%s", ident);
Everything should be fine by then.

How do I free up the memory consumed by a string literal?

How do I free up all the memory used by a char* after it's no longer useful?
I have some struct
struct information
{
/* code */
char * fileName;
}
I'm obviously going to save a file name in that char*, but after using it some time afterwards, I want to free up the memory it used to take, how do I do this?
E: I didn't mean to free the pointer, but the space pointed by fileName, which will most likely be a string literal.
There are multiple string "types" fileName may point to:
Space returned by malloc, calloc, or realloc. In this case, use free.
A string literal. If you assign info.fileName = "some string", there is no way. The string literal is written in the executable itsself and is usually stored together with the program's code. There is a reason a string literal should be accessed by const char* only and C++ only allows const char*s to point to them.
A string on the stack like char str[] = "some string";. Use curly braces to confine its scope and lifetime like that:
struct information info;
{
char str[] = "some string";
info.fileName = str;
}
printf("%s\n", info.fileName);
The printf call results in undefined behavior since str has already gone out of scope, so the string has already been deallocated.
You could use foo.fileName = malloc(howmanychars); and free(foo.fileName);.
You cannot free the memory if you initialize fileName from a string literal or other non-dynamically allocated way.
But then, freeing a handful of bytes is next to pointless, unless you need a large number of such structs/fileNames. The OS will likely not return the freed memory to other processes; the returned memory may be available for future memory allocations of your process.

Assigning character to char[x] results in segmentation fault

I have already written a couple of C programs and consider this awkward to ask. But why do I receive a segmentation fault for the following code being supposed to replace "test" by "aaaa"?
#include <stdio.h>
int main(int argc, char* argv[])
{
char* s = "test\0";
printf("old: %s \n", s);
int x = 0;
while(s[x] != 0)
{
s[x++] = 'a'; // segmentation fault here
}
printf("new: %s \n", s); // expecting aaaa
return 0;
}
This assignment is writing to a string literal, which is stored in a read-only section of your executable when it is loaded in memory.
Also, note that the \0 in the literal is redundant.
One way to fix this (as suggested in comments) without copying the string: declare your variable as an array:
char s[] = "test";
This will cause the function to allocate at least 5 bytes of space for the string on the stack, which is normally writeable memory.
Also, you should generally declare a pointer to a string literal as const char*. This will cause the compiler to complain if you try to write to it, which is good, since the system loader will often mark the memory it points to as read-only.
Answering the OP's question in the comment posted to #antron.
What you need is to allocate a character array, then use strcpy() to initialize it with your text, then overwrite with a-s.
Allocation can be done statically (i.e., char s[10];) but make sure the space is enough to store the length of your init string (including the terminating \0).
Alternatively, you can dynamically allocate memory using malloc() and free it using free(). This enables you to allocate exactly enough space to hold your init string (figure it out in run-time using strlen()).

Resources