Segmentation fault when dividing string using malloc - c

I am using ncurses to create my own terminal. I get the string and save it in a 2D array, buffer[80][256]. I get the string using getstr(buffer[i]). Then I have the following in the main function;
while (strcmp(buffer[i],"exit")!=0) {
strcpy(command,buffer[i]);
printw("%s\n",command);
//calls the function commands found in another source file
commands(buffer[i]);
mvwin(childwin, y, x);
wnoutrefresh(childwin);
i++;
printw("%s",prompt);
getstr(buffer[i]);
doupdate();
}
//source file where one finds commands;
//global array
char*final[40];
void commands (char input[]){
char **buffer =split(input);
...
}
//creating segmentation fault
char **split(char input[]){
char *ptr;
int i=0;
ptr = strtok(input," ");
while(split != NULL){
final[i] = malloc(strlen(ptr)+1);
strcpy(final[i],ptr);
ptr = strtok(NULL," ");
i++;
}
return final;
}
What the above function is doing; it is receiving the input by the user buffer[i] and it is dividing the strings into separate elements within array buffer in function commands. e.g. if the user enters print hello my name is, buffer in function commands with hold; buffer[0] = print, buffer[1] = hello buffer[2] = my ....
From my testing it seems like the malloc is the thing causing it, but I have no idea on how to solve it.
Thank you very much in advance.

while(split != NULL){
Instead of check split for NULL you need to check if ptr is NULL.
If it is NULL then your malloc will allocate 1 byte and memory's dereference will cause problems due to overflow.

Related

Segmentation fault in accessing & modifying string (char*) array in C

I've been getting segmentation faults (with gdb printing "??" on backtraces) on a program I'm trying to compile for a while now and after trying many things (such re-programming a data structure I used which should work now) I still kept getting segfaults although now it gave me a line (which I added a comment onto here).
getMains() is ran multiple times to tokenize different lines from the same file.
I wanted mains to be an array of size 4 but when passing it as "char * mains[4]" I I got a compile error for trying to pass it an array (*)[4] which I've never dealt with beforehand (Just started using C). I'm assuming maybe that could be a problem if I try to access any part that wasn't used, but the problem happens while initializing the indices of the array.
The code I'm trying to get to work, where the "char *** mains" argument is taking in a &(char **) from a separate function "runner" which I want to be edited so I can look at its contents in "runner":
bool getMains(FILE * file, char *** mains)
{
char line[256];
int start = 0;
char * token;
const char * mainDelim = "\t \n\0", * commDelim = "\n\t\0";
if(fgets(line, sizeof(line), file) == NULL)
return false;
while(line[0] == '.')
if(fgets(line, sizeof(line), file) == NULL);
return false;
if(line[0] == '\t' || line[0] == ' ')
{
(*mains)[0] = " ";
start = 1;
}
token = strtok(line, mainDelim);
int i;
for(i = start; token != NULL; ++i)
{
(*mains)[i] = strdup(token); // <- gdb: Segmentation Fault occurs here
if(i % 3 == 2)
token = strtok(NULL, commDelim);
else
token = strtok(NULL, mainDelim);
}
free(token); // Unsure if this was necessary but added in case.
return true;
}
/* Snippet of code running it... */
void runner(FILE * file) {
char ** mains;
if(!getMains(*file, &mains))
return;
while(strcmp(mains[1], "END") != 0){
/* do stuff lookinig through indices 0, 1, 2, & 3 */
if(!getMains(*file, &mains))
break;
}
}
Any tips on this or just generally safely modifying arrays through other functions?
Should I change getMains() into "getMains(FILE * file, char ** mains[4]);" and pass it a &"char * mains[4]") for it to be a set size as wanted? Or would that also produce errors?
You need to allocate memory for mains, it should look like this:
char ** mains;
mains = malloc(some number N * sizeof(char*));
You need something like this if you don't use strdup, which allocates the memory for you:
for (int i = 0; i < N; ++i) {
mains[i] = malloc(some number K);
}
In all cases, do not forget to call free on every pointer you received from malloc or strdup. You can skip this part if the program ends right after you would call free.

Segfault in C program, malloc call

I am writing a program that takes a list of path ( environmental variable), splits the paths and prints it. When compiling it I get a segfault. The following is my output on GDB :
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400eb0 in dest (name=0x7fffffffbce0 "PATH") at executables.c:100
100 dest[i] = malloc(srclen+1);
On valgrind:
==21574== 1 errors in context 2 of 3:
==21574== Use of uninitialised value of size 8
==21574== at 0x400EB0: dest (executables.c:100)
==21574== by 0x400B5B: main (main.c:9)
This is my function:
char** dest(char *name){
int i=0;
char *vp;
const char s[2]=":";
char *token;
char **dest;
name[strlen(name)-1]='\0';
vp=getenv(name);
if(vp == NULL){
exit(1);
}
token =strtok(vp,s);
while( token != NULL ){
size_t srclen = strlen(token);
dest[i] = malloc(srclen+1);
strcpy(dest[i], token);
token = strtok(NULL, s);
i++;
}
dest[i]=NULL;
return dest;
}
And this is my main:
#include "executables.h"
int main(int argc, char **argv){
char *path;
char name[BUFSIZ];
printf("enter name of environment variable:\n");
fgets(name,BUFSIZ,stdin);
char **p=dest(name);
int j=0;
while(p[j]!=NULL){
printf("%s\n",p[j]);
j++;
}
return(0);
}
Use strdup(). Saves steps (accounts for
'\0' too). You have to allocate some memory before hand for the approach you're using. Otherwise you might want a linked list and allocate packets instead of using the array pattern. When you say dest[i] = <ptr value> you're indexing to an offset of unallocated memory and storing something there, so it's a segvio.
#include <string.h>
#define MAXTOKENS 10000
char **get_dest(char *name) {
// Since dest has to be exposed/persist beyond this function all
// need dynamically allocate (malloc()) rather than stack allocate
// of the form of: char *dest[MAXTOKENS].
char *dest = malloc(MAXTOKENS * sizeof (char *)); // <--- need to allocate storage for the pointers
char *vp;
if ((vp = getenv(name)) == NULL)
exit(-1); // -1 is err exit on UNIX, 0 is success
int i = 0;
char *token = strtok(vp, ":");
while (token != NULL) {
dest[i] = strdup(token); // <=== strdup()
token = strtok(NULL, ":");
i++;
}
// dest[i] = NULL; // Why are you setting this to NULL after adding token?
return dest;
}
It's better if main() takes care of passing a proper null-terminated string to the get_dest() function because main is where the finicky fgets() is handled. Generally you want to do things locally where it makes the most sense and is most relevant. If you ever took your get_dest() function and used it somewhere where the strings were not read by fgets() it would just be a wasted step to overwrite the terminator there. So by initializing the char array to zeroes before fgets() you don't have to worry about setting the trailing byte to '\0'.
And finally probably not good to have your function name dest the same name as the variable it returns dest. In some situations having multiple symbols in your program with the same name can get you into trouble.
#include "executables.h"
int main(int argc, char **argv) {
char *path;
char name[BUFSIZ] = { 0 }; // You could initialize it to zero this way
printf("enter name of environment variable:\n");
// bzero(name, BUFSIZ); //... or you could initialize it to zero this way then
fgets(name, BUFSIZ, stdin);
char **p = get_dest(name);
int j = 0;
while(p[j] != NULL) {
printf("%s\n", p[j]);
j++;
free(p[j]); // like malloc(), strdup'd() strings must be free'd when done
}
free(p);
return 0;
}
dest[i] = malloc(srclen + 1);
You need to allocate memory for the pointer to char pointers (dest) as well as each char pointer stored in dest. In the code you provided, neither step is taken.
From the manpage of getenv:
Notes
...
As typically implemented, getenv() returns a pointer to a string
within the environment list. The caller must take care not to modify
this string, since that would change the environment of the process.
Your code violates that rule:
vp=getenv(name);
...
token =strtok(vp,s);
This is an illegal memory write operation.

Segmentation fault when calling fgets to read lines from file

I'm getting a seg fault when after calling fgets about 20 times. I'm opening a file (does not return null). It is in the format:
num1: value1
num2: value2
num3: value3
then reading lines from the file, storing values into an array, using nums as positions. Here is the code that seg faults:
edit: declaring myArray and line:
char myArray[3000];
char * line;
char * word;
line = (char *) malloc(100);
word = (char *) malloc(16);
while(fgets(line, 99, file)) {
printf("%s\n", line);
word = strtok(line, " :");
name = (int) strtol(word, NULL, 16);
word = strtok(NULL, " \n");
myArray[name] = word;
}
you'll notice I print out the line immediately after getting it. The file has 26 lines, but it only prints 23 line and then seg faults. Now, is it something I don't fully understand about fgets, or am I getting some synthax incorrect? I've tried allocating more memory to line, or more to word. I've also tried malloc -ing more memory after every call to strtok, but nothing seems to fix the seg fault.
The problems is the line myArray[name] = word; you're taking an array index from your input line and then setting the character at that position to low bits of the address of your word... I doubt that's actually what you want to do.
There's some other problems with your code, you're leaking the memory from the line word = (char *) malloc(16); because strtok returns a pointer into the string you initially pass it. You don't actually need to malloc anything for the code as written in the question, so you could have:
char myArray[3000];
char line[100];
char *word = NULL;
word needs to be a pointer since it's holding the result of strtok()
You clearly don't understand pointers, you need to review that before you can understand why your code isn't working the way you expect.
If you say what your code is actually meant to be doing I can give you some hints on how to fix it, but at the moment I can't quite tell what the intended result is.
EDIT: Did you intend to read in your numbers in hexadecimal? The last argument to strtol() is the base to be used for conversion... you could also just use atoi()
so your loop could look like:
char myArray[3000];
char line[100];
char *word = NULL;
while(fgets(line, 100, file)) {
printf("%s\n", line);
word = strtok(line, " :");
if(word == NULL) continue;
name = atoi(word); /* only if you didn't actually want hexadecimal */
word = strtok(NULL, " \n");
if(word == NULL) continue;
if(name > 0 && name < 3000) { /* as I said in a comment below */
strncpy(myArray + name, word, 3000 - name);
}
}

realloc not working for 2-D pointer array

In the following code, I ask the user to give me some strings. I make a 2-D pointer char array, so that I read the input with pointer string which points to the start of a string of length 50. My problem is that I keep crashing after the input of the first string.. and I assume that my problem has to do with the realloc. I am not used to it.. can you please help to figure out what is happening?? I tried to debug with netbeans, but didn't manage to see anything interesting, since it doesn't give feedback for the new addresses made from realloc!!
Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *str,**string,buffer[50],temp[2];
int i,j,q,size,counter;
size=10;
string=(char**) calloc(size,sizeof(char*));
for (i=0; i<size; i++) string[i]=(char*) malloc(50*sizeof(char));
printf("\nGimme strings, terminate input with x");
i=0;
gets(string[i]);
temp[0]=120;//x
temp[1]='\0';
size=0;
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
return 0;
}
I want to make the table of pointers bigger with this realloc.
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
After you call realloc to enlarge string, the new portion contains no valid pointers. So when you call gets, you're passing it a pointer you failed to initialize.
Also, that size=0; is totally broken.
realloc does not initialize the allocated memory with zeros, in addition you forgot to initialize the newly allocated string pointers.
Consider to move up i++ and size++ within the while loop.
Code Review
initialize all your variables
char *str = NULL,**string = NULL,buffer[50] = {0},temp[2] = {0};
int i = 0,j = 0,q = 0,size = 10,counter = 0;
do not cast what is returned from malloc/calloc and use {} when possible for clarity
string=calloc(size,sizeof(char*));
for (i=0; i<size; i++)
{
string[i]=malloc(50*sizeof(char));
}
When reading from the keyboard do not use gets, use fgets() since you can specify the max size to read.
printf("\nGimme strings, terminate input with x");
char input[256];
fgets(input,sizeof(input),stdin); // another varname, will explain below
With newer compilers you can declare variables where you need them instead of decl at top of function.
char temp={'x','\0'}; // 120;//x
setting size=0 here seems a bit strange
size=0;
it is better to keep what the user inputs in a separate buffer (input)
then if it is not "x" copy it into your string array so instead of
while(strcmp(string[i],temp)!=0)
{
string=realloc(string,size*sizeof(char**));
i++;
gets(string[i]);
size++;
counter++;
}
e.g.
while (fgets(input,sizeof(input),stdin) != NULL && input[0] != 'x')
{
string[i] = calloc(1,strlen(input)+1); // add a byte for \0
strncpy(string[i],input,strlen(input)-1); // not copying ending \n
if ( ++i == size ) // a new chunk needed
{
char *newstring = realloc((size + 10)*sizeof(char*), string );
if ( newstring != NULL )
{
string = newstring;
size += 10;
}
}
}

how to put char * into array so that I can use it in qsort, and then move on to the next line

I have lineget function that returns char *(it detects '\n') and NULL on EOF.
In main() I'm trying to recognize particular words from that line.
I used strtok:
int main(int argc, char **argv)
{
char *line, *ptr;
FILE *infile;
FILE *outfile;
char **helper = NULL;
int strtoks = 0;
void *temp;
infile=fopen(argv[1],"r");
outfile=fopen(argv[2],"w");
while(((line=readline(infile))!=NULL))
{
ptr = strtok(line, " ");
temp = realloc(helper, (strtoks)*sizeof(char *));
if(temp == NULL) {
printf("Bad alloc error\n");
free(helper);
return 0;
} else {
helper=temp;
}
while (ptr != NULL) {
strtoks++;
fputs(ptr, outfile);
fputc(' ', outfile);
ptr = strtok(NULL, " ");
helper[strtoks-1] = ptr;
}
/*fputs(line, outfile);*/
free(line);
}
fclose(infile);
fclose(outfile);
return 0;
}
Now I have no idea how to put every of tokenized words into an array (I created char ** helper for that purpose), so that it can be used in qsort like qsort(helper, strtoks, sizeof(char*), compare_string);.
Ad. 2 Even if it would work - I don't know how to clear that line, and proceed to sorting next one. How to do that?
I even crashed valgrind (with the code presented above) -> "valgrind: the 'impossible' happened:
Killed by fatal signal"
Where is the mistake ?
The most obvious problem (there may be others) is that you're reallocating helper to the value of strtoks at the beginning of the line, but then incrementing strtoks and adding to the array at higher values of strtoks. For instance, on the first line, strtoks is 0, so temp = realloc(helper, (strtoks)*sizeof(char *)); leaves helper as NULL, but then you try to add every word on that line to the helper array.
I'd suggest an entirely different approach which is conceptually simpler:
char buf[1000]; // or big enough to be bigger than any word you'll encounter
char ** helper;
int i, numwords;
while(!feof(infile)) { // most general way of testing if EOF is reached, since EOF
// is just a macro and may not be machine-independent.
for(i = 0; (ch = fgetc(infile)) != ' ' && ch != '\n'; i++) {
// get chars one at a time until we hit a space or a newline
buf[i] = ch; // add char to buffer
}
buf[i + 1] = '\0' // terminate with null byte
helper = realloc(++numwords * sizeof(char *)); // expand helper to fit one more word
helper[numwords - 1] = strdup(buffer) // copy current contents of buffer to the just-created element of helper
}
I haven't tested this so let me know if it's not correct or there's anything you don't understand. I've left out the opening and closing of files and the freeing at the end (remember you have to free every element of helper before you free helper itself).
As you can see in strtok's prototype:
char * strtok ( char * str, const char * delimiters );
...str is not const. What strtok actually does is replace found delimiters by null bytes (\0) into your str and return a pointer to the beginning of the token.
Per example:
char in[] = "foo bar baz";
char *toks[3];
toks[0] = strtok(in, " ");
toks[1] = strtok(NULL, " ");
toks[2] = strtok(NULL, " ");
printf("%p %s\n%p %s\n%p %s\n", toks[0], toks[0], toks[1], toks[1],
toks[2], toks[2]);
printf("%p %s\n%p %s\n%p %s\n", &in[0], &in[0], &in[4], &in[4],
&in[8], &in[8]);
Now look at the results:
0x7fffd537e870 foo
0x7fffd537e874 bar
0x7fffd537e878 baz
0x7fffd537e870 foo
0x7fffd537e874 bar
0x7fffd537e878 baz
As you can see, toks[1] and &in[4] point to the same location: the original str has been modified, and in reality all tokens in toks point to somewhere in str.
In your case your problem is that you free line:
free(line);
...invalidating all your pointers in helper. If you (or qsort) try to access helper[0] after freeing line, you end up accessing freed memory.
You should copy the tokens instead, e.g.:
ptr = strtok(NULL, " ");
helper[strtoks-1] = malloc(strlen(ptr) + 1);
strcpy(helper[strtoks-1], ptr);
Obviously, you will need to free each element of helper afterwards (in addition to helper itself).
You should be getting a 'Bad alloc' error because:
char **helper = NULL;
int strtoks = 0;
...
while ((line = readline(infile)) != NULL) /* Fewer, but sufficient, parentheses */
{
ptr = strtok(line, " ");
temp = realloc(helper, (strtoks)*sizeof(char *));
if (temp == NULL) {
printf("Bad alloc error\n");
free(helper);
return 0;
}
This is because the value of strtoks is zero, so you are asking realloc() to free the memory pointed at by helper (which was itself a null pointer). One outside chance is that your library crashes on realloc(0, 0), which it shouldn't but it is a curious edge case that might have been overlooked. The other possibility is that realloc(0, 0) returns a non-null pointer to 0 bytes of data which you are not allowed to dereference. When your code dereferences it, it crashes. Both returning NULL and returning non-NULL are allowed by the C standard; don't write code that crashes regardless of which behaviour realloc() shows. (If your implementation of realloc() does not return a non-NULL pointer for realloc(0, 0), then I'm suspicious that you aren't showing us exactly the code that managed to crash valgrind (which is a fair achievement — congratulations) because you aren't seeing the program terminate under control as it should if realloc(0, 0) returns NULL.)
You should be able to avoid that problem if you use:
temp = realloc(helper, (strtoks+1) * sizeof(char *));
Don't forget to increment strtoks itself at some point.

Resources