Is your "update" example complete? I wouldn't think that would compile: it calls for a return value but you never return anything. You never do anything will fullpath, but perhaps that's deliberate, maybe your point is just to say that when you do the malloc, other things break.
Without seeing the caller, it's impossible to say definitively what is happening here. My guess is that paths is a dynamically-allocated block that was free'd before you called this function. Depending on the compiler implementation, a free'd block could still appear to contain valid data until a future malloc takes over the space.
Update: to actually answer the question
String handling is a well-known problem in C. If you create a fixed-size array to hold the string, you have to worry about a long string overflowing the allocated space. This means constantly checking string sizes on copies, using strncpy and strncat instead of the plain strcpy and strcat, or similar techniques. You can skip this and just say, "Well, no one would ever have a name longer than 60 characters" or some such, but there's always the danger then that someone will. Even on something that should have a known size, like a social security number or an ISBN, someone could make a mistake entering it and hit a key twice, or a malicious user could deliberately enter something long. Etc. Of course this is mostly an issue on data entry or reading files. Once you have a string in a field of some known size, then for any copies or other manipulation, you know the size.
The alternative is to use dynamically-allocated buffers where you can make them as big as needed. This sounds like a good solution when you first hear it, but in practice it's a giantic pain in C, because allocating the buffers and freeing them when you no longer need them is a lot of trouble. Another poster here said that the function that allocates a buffer should be the same one that frees it. A good rule of thumb, I generally agree, but ... What if a subroutine wants to return a string? So it allocates the buffer, returns it, and ... how can it free it? It can't because the whole point is that it wants to return it to the caller. The caller can't allocate the buffer because it doesn't know the size. Also, seemingly simple things like:
if (strcmp(getMeSomeString(),stringIWantToCompareItTo)==0) etc
are impossible. If the getMeSomeString function allocates the string, sure, it can return it so we do the compare, but now we've lost the handle and we can never free it. You end up having to write awkward code like
char* someString=getMeSomeString();
int f=strcmp(someString,stringIWantToCompareItTo);
free(someString);
if (f==0)
etc
So okay, it works, but readability just plummetted.
In practice, I've found that when strings can reasonably be expected to be of a knowable size, I allocate fixed-length buffers. If an input is bigger than the buffer, I either truncate it or give an error message, depending on the context. I only resort to dynamically-allocated buffers when the size is potentially large and unpredictable.