Segmentation fault when using strcpy? - c

I'm trying to define a path at compile time by passing:
-DDCROOTDEF='"/path/to/stuff"'
on the compile line. I then try to get use this in the code like:
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
char *pftf=ptr_path;
gdImageStringFT(pimg,brect,iclr,pftf,pts,ang,ixp,iyp, (char *)cbuf);
Which gives me a segmentation fault. However, if I try to print the string first:
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
char *pftf=ptr_path;
printf("%s\n",pftf);
gdImageStringFT(pimg,brect,iclr,pftf,pts,ang,ixp,iyp, (char *)cbuf);
It works just fine. What intricacy of char pointer's am I missing here?
Thanks

char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
You never initialize ptr_path.
It doesn't work in the second code snippet, you are just getting unlucky and it appears to work. You're still using an uninitialized pointer and trying to write to who knows where in memory.
You need to initialize ptr_path to point to an array of char that is at least strlen(DCROOTDEF) + 1 in length. You also need to check the length of DCROOTDEF before copying its contents into the array to be sure that it is not too long. You can do so manually using strlen or you can use a length-checked copy function like strlcpy.

The pointer ptr_path is not initialized to point at writable memory, which is why dereferencing it using strcpy() is crashing.
You need to call e.g. malloc() to get the space, first:
char * ptr_path = malloc(PATH_MAX);
Or something like that.

In
char * ptr_path;
strcpy(ptr_path, DCROOTDEF);
strcat(ptr_path,"/MainCommons/CommonLib/fonts/Arial.ttf");
the pointer is not bound to a legally allocated block of memory, so your program runs into undefined behavior. You need to allocate a buffer first - for example by using malloc(). Be sure that the buffer is large enough to hold the resulting string together with the terminating null character.

Related

Why does malloc seemingly allow me to write over memory? [duplicate]

This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 4 years ago.
Why does this not return a segmentation fault 11?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char *test;
test = (char*) (malloc(sizeof(char)*3));
test = "foo";
printf("%s\n", test);
test = "foobar";
printf("%s\n", test);
return 0;
}
My outcome is
foo
foobar
I'm fairly new to C, but when I was compiling this using both gcc on mac and Windows Debugger on Windows 10, it doesn't crash like I expected.
My understanding is that by using (char*) (malloc(sizeof(char)*3)), I am creating a character array of length 3. Then, when I assign test to the string foobar I am writing to 6 array positions.
I'm left sitting here, staring at my apparently valid, runnable code scratching my head.
test = "foo";
Here you do not copy the string to the allocated memory, test no longer points to the allocated memory, instead it points to the string literal "foo". Same goes for "foobar". Also as pointed out in the comments the address of the allocated memory is lost and therefore it is a memory leak (since there is no way to retrieve the address of the memory).
If you want to copy a string to another destination you need to use strcpy or loop over every character.
If you write or read outside bounds of the allocated space you are invoking undefined behavior. That means that basicly everything can happen, also that it works.
Your program never writes to the location pointed to by the return from malloc(). All you've done with e.g. test = "foo"; is change what test points to, which by the way is a memory leak since you've then lost what malloc() returned.
To properly use the memory you allocated with malloc(), use strcpy(), snprintf(), etc.
Also, don't forget the null terminator in your C strings. To properly store e.g. "foobar" you need at least 7 bytes, not 6.
First thing is that you waste the memory allocated by malloc unnecessorily by storing the address of foo into that.
If you are going to point to string in code section then there is no need to allocate memory to the pointer.
When to allocate memory to pointer
e.g. when you intended to scan 'n' number of bytes from keyboard in pointer.
char *ptr,num_char;
scanf("%d",&num_char);
ptr = (char *)malloc(num_char*sizeof(char));
scanf("%s",ptr);

Copying part of char array into new char array fails

I want to copy a part of char array into a new one
void match(char* probe, char* pattern)
char* matchText;
//the char-array probe in this example is at least 12 characters long
//I'm only writing numbers in the strncopy-command to make it easier to understand
strncpy (matchText, probe + 5, 5 );
Upon running that the debugger quits with an error.
What am I doing wrong?
You need to allocate memory to matchText, what you have is just an pointer.
It must have enough memory allocated using malloc(since it is a pointer) to hold the string being copied in to it, or what you get is Undefined Behavior.

C char* pointers pointing to same location where they definitely shouldn't

I'm trying to write a simple C program on Ubuntu using Eclipse CDT (yes, I'm more comfortable with an IDE and I'm used to Eclipse from Java development), and I'm stuck with something weird. On one part of my code, I initialize a char array in a function, and it is by default pointing to the same location with one of the inputs, which has nothing to do with that char array. Here is my code:
char* subdir(const char input[], const char dir[]){
[*] int totallen = strlen(input) + strlen(dir) + 2;
char retval[totallen];
strcpy(retval, input);
strcat(retval, dir);
...}
Ok at the part I've marked with [*], there is a checkpoint. Even at that breakpoint, when I check y locals, I see that retval is pointing to the same address with my argument input. It not even possible as input comes from another function and retval is created in this function. Is is me being unexperienced with C and missing something, or is there a bug somewhere with the C compiler?
It seems so obvious to me that they should't point to the same (and a valid, of course, they aren't NULL) location. When the code goes on, it literally messes up everything; I get random characters and shapes in console and the program crashes.
I don't think it makes sense to check the address of retval BEFORE it appears, it being a VLA and all (by definition the compiler and the debugger don't know much about it, it's generated at runtime on the stack).
Try checking its address after its point of definition.
EDIT
I just read the "I get random characters and shapes in console". It's obvious now that you are returning the VLA and expecting things to work.
A VLA is only valid inside the block where it was defined. Using it outside is undefined behavior and thus very dangerous. Even if the size were constant, it still wouldn't be valid to return it from the function. In this case you most definitely want to malloc the memory.
What cnicutar said.
I hate people who do this, so I hate me ... but ... Arrays of non-const size are a C99 extension and not supported by C++. Of course GCC has extensions to make it happen.
Under the covers you are essentially doing an _alloca, so your odds of blowing out the stack are proportional to who has access to abuse the function.
Finally, I hope it doesn't actually get returned, because that would be returning a pointer to a stack allocated array, which would be your real problem since that array is gone as of the point of return.
In C++ you would typically use a string class.
In C you would either pass a pointer and length in as parameters, or a pointer to a pointer (or return a pointer) and specify the calls should call free() on it when done. These solutions all suck because they are error prone to leaks or truncation or overflow. :/
Well, your fundamental problem is that you are returning a pointer to the stack allocated VLA. You can't do that. Pointers to local variables are only valid inside the scope of the function that declares them. Your code results in Undefined Behaviour.
At least I am assuming that somewhere in the ..... in the real code is the line return retval.
You'll need to use heap allocation, or pass a suitably sized buffer to the function.
As well as that, you only need +1 rather than +2 in the length calculation - there is only one null-terminator.
Try changing retval to a character pointer and allocating your buffer using malloc().
Pass the two string arguments as, char * or const char *
Rather than returning char *, you should just pass another parameter with a string pointer that you already malloc'd space for.
Return bool or int describing what happened in the function, and use the parameter you passed to store the result.
Lastly don't forget to free the memory since you're having to malloc space for the string on the heap...
//retstr is not a const like the other two
bool subdir(const char *input, const char *dir,char *retstr){
strcpy(retstr, input);
strcat(retstr, dir);
return 1;
}
int main()
{
char h[]="Hello ";
char w[]="World!";
char *greet=(char*)malloc(strlen(h)+strlen(w)+1); //Size of the result plus room for the terminator!
subdir(h,w,greet);
printf("%s",greet);
return 1;
}
This will print: "Hello World!" added together by your function.
Also when you're creating a string on the fly you must malloc. The compiler doesn't know how long the two other strings are going to be, thus using char greet[totallen]; shouldn't work.

Segmentation fault around strcpy?

I know that you will rap me over the knuckles but.
Why does it make Segmentation fault
char* cmd;
strcpy(cmd, argv[0]);
when this doesn't
char *cmd;
cmd = "plop";
I didn't practice since a while, and can't remember why.
ps: actually, i know that something like that, before the strcpy, would be better
char *cmd = (char*) malloc(strlen(argv[0]));
but i'm just wondering why this segmentation fault.
Thanks !
When you do:
char * cmd;
You're allocating a pointer on the stack. This pointer is not initialized to any meaningful value.
Then, when you do this:
strcpy(cmd, argv[0]);
You copy the string contained in argv[0] to the address pointed to cmd, which is... something meaningless. Since you're lucky, it simply segfaults.
When you do this:
cmd = "plop";
You assign to cmd the address to a statically allocated string constant. Since such strings are read only, writing on them is undefined behavior.
So, how to solve this? Allocate memory for the runtime to write to. There's two ways:
The first one is to allocate data on the stack, like this:
char cmd[100]; // for instance
This allocates an array of 100 chars on the stack. However, it's not necessarily robust, because you must know in advance how much memory you'll need. The stack is also smaller than the heap. Which leads us to option number 2:
char *cmd = malloc(whatever_you_need); // no need to cast, by the way, unless you're in C++
This allocates whatever_you_need chars on the heap. Don't forget to release the memory with free once you're done with it.
You get a seg. fault because cmd in your first example isn't pointing to anything (or, rather, it's pointing to something that's undefined - so attempting to read characters from or write characters to the pointer will probably result in an access violation).
In the second example, you're setting cmd to point to a legitimate string of chars.
If you want to make copy of argv[0] easily,
char* cmd = strdup(argv[0]);
Of course, you have better to check result of strdup is null or not. :)
i'm just wondering why this segmentation fault.
Because if cmd is a global variable, its value is NULL, which is not writable, and if it's a local variable, then its value is indeterminate and you should not use it (but it can do anything if you do, which is worse than NULL in many cases).

Char* p, and scanf

I have been trying to look for a reason why the following code is failing, and I couldn't find one.
So please, excuse my ignorance and let me know what's happening here.
#include<stdio.h>
int main(void){
char* p="Hi, this is not going to work";
scanf("%s",p);
return 0;
}
As far as I understood, I created a pointer p to a contiguous area in the memory of the size 29 + 1(for the \0).
Why can't I use scanf to change the contents of that?
P.S Please correct me If I said something wrong about char*.
char* p="Hi, this is not going to work";
this does not allocate memory for you to write
this creates a String Literal which results inUndefined Behaviour every time you try to change its contents.
to use p as a buffer for your scanf do something like
char * p = malloc(sizeof(char) * 128); // 128 is an Example
OR
you could as well do:
char p[]="Hi, this is not going to work";
Which I guess is what you really wanted to do.
Keep in mind that this can still end up being UB because scanf() does not check whether the place you are using is indeed valid writable memory.
remember :
char * p is a String Literal and should not be modified
char p[] = "..." allocates enough memory to hold the String inside the "..." and may be changed (its contents I mean).
Edit :
A nice trick to avoid UB is
char * p = malloc(sizeof(char) * 128);
scanf("%126s",s);
p points to a constant literal, which may in fact reside in a read-only memory area (implementation dependent). At any rate, trying to overwrite that is undefined behaviour. I.e. it might result in nothing, or an immediate crash, or a hidden memory corruption which causes mysterious problems much later. Don't ever do that.
It is crashing because memory has not been allocated for p. Allocate memory for p and it should be ok. What you have is a constant memory area pointing to by p. When you attempt to write something in this data segment, the runtime environment will raise a trap which will lead to a crash.
Hope this answers your question
scanf() parses data entered from stdin (normally, the keyboard). I think you want sscanf().
However, the purpose of scanf() is to part a string with predefined escape sequences, which your test string doesn't have. So that makes it a little unclear exactly what you are trying to do.
Note that sscanf() takes an additional argument as the first argument, which specifies the string being parsed.

Resources