I have been debugging a piece of legacy code, running on an XScale (arm v5te) System with linux, that crashes reproducible.
I have debugged using gdb and set MALLOC_CHECK_ to 1. It's a lot of code, so just some snippets:
We have this structure:
typedef struct {
...clipped..
char **data_column_list;
/** data column count */
int data_column_cnt;
...clipped
} csv_t;
We initialize the columns in a function, putting them in a variable "columns"
/* Allocating memory for pointer to every register id */
columns = (char **) malloc(column_cnt * sizeof(char *));
column_cnt = 0;
/* loop over all sensors */
for(i=0; i<cfg.sen_cnt; i++) {
/* loop over all registers */
for(j=0; j<cfg.sen_list[i]->data_cnt; j++) {
/* Storing all the pointers to id */
columns[column_cnt++] = cfg.sen_list[i]->data_list[j]->id;
}
}
In another function, what happens is this:
/* free the previous list */
csv_free(lc_csv);
lc_csv->data_column_list = columns;
lc_csv->data_column_cnt = column_cnt;
csv_free being:
void csv_free(csv_t *csv) {
if(csv->data_column_cnt > 0)
free(csv->data_column_list);
csv->data_column_cnt = 0;
}
Now, there is another function, building the whole "cfg"/config structure, that contains these ids.
Code frome above: cfg.sen_list[i]->data_list[j]->id; where cfg is a struct, sen_list is an array of pointers to structs, data_list is an array of pointers to other structs, that contain a string "id".
Whe the program gets a signal SIGUSR1, the config is being updated. All of these data_list and sen_list structs are being freed, then new ones are generated.
Then with the first function, new collumns of ids are generated and put into the csv structure, but the old list is being freed before.
Thats where it crashes. In csv_free.
*** glibc detected *** /root/elv: free(): invalid pointer: 0x0001ae88 ***
I thought it should be like this. You have an array of pointers. When you free the pointers, you have to free the pointer, pointing to a set of pointers (the array).
Or put in code terms, the above situation should be analog to:
char **ar = malloc(n * sizeof(char *));
char *xn = malloc(10 * sizeof(char)); // Do for 0 to n strings
...
ar[n] = xn; // Do for 0 to n strings
...do stuff...
free(xn); // Do for 0 to n strings
free(ar);
When the structs, containing the id strings, are freed, I still have my pointer arrays with (invalid) pointers, not null pointers:
(gdb) p csv
$40 = {sysid = 222, ip = '\0' <repeats 49 times>,
module = "elv_v2", '\0' <repeats 14 times>, format_type = 1, msg_id = 0,
data_column_list = 0x1ae88, data_column_cnt = 10, pub_int = 30,
line_cnt = 0, pub_seq = -1, format = 0x18260}
(gdb) p csv.data_column_list[0]
$41 = 0x1b378 "0"
But I get the above error message (or SIGABRT without the MALLOC_CHECK_).
I don't understand this at all. I have to free this array of pointers, or it will become a memory leak. There is no other call of free before that, that I could find. I don't know why csv.data_column_list is considered an invalid pointer.
Valgrind is unfortunately not availiable on arm v5te :(
Have been debugging this for hours and hours and would be happy for any help.
Thank you very much,
Cheers,
Ben
UPDATE:
I'm wondering if it could be connected to some "scope" issue. There is almost identical code in another application, which works. The function which crashes, "csv_free" is used by both programs (statically linked). The only difference is, that the struct containing the pointer to be freed is declared and defined normally in the working program and declared as external and defined in another file than main.c
Calling "free" manually in main.c works, while calling "csv_free" crashes. Riddle me this...
9 out of 10 times when I run into free() errors the problem actually started in the allocation or initialization, so let's verify that a bit:
Where do you actually assign columns to csv.data_columns_list before you call csv_free? If it's uninitialized when you free(), that would explain the error.
In the second code block, if the initial column_cnt (which I guess is set
elsewhere?) is less than the column_cnt after the loop you would be writing outside the
array. One would hope MALLOC_CHECK_ would catch that, but what happens if you assert as
follows:
/* Allocating memory for pointer to every register id */
columns = (char **) malloc(column_cnt * sizeof(char *));
int old_column_cnt = column_cnt;
column_cnt = 0;
/* loop over all sensors */
for(i=0; i<cfg.sen_cnt; i++) {
/* loop over all registers */
for(j=0; j<cfg.sen_list[i]->data_cnt; j++) {
/* Storing all the pointers to id */
columns[column_cnt++] = cfg.sen_list[i]->data_list[j]->id;
}
}
assert(old_column_cnt >= column_cnt);
Looking over my old questions I saw this. I can't really verify, since I don't work at that company anymore, but thinking of other issues we had, I think wildplasser was right.
Calling any large functions from within signal handlers is a bad idea. Especially if you haven't check whether everything you do is reentrant. It was legacy code, so at least it's not completely my fault ;)
Nowadays I would set a flag in the signal handler and call the routine in my main loop, when that flag is set (or something like that).
Related
I need to make an array of structs dynamically and I don't know the size when executing the malloc command. So I thought I could use realloc every time I need another struct! For example this code:
main:
int main(void) {
flights *flight_list = NULL;
int numFlights = 0;
numFlights = load_flights(&flight_list);
/* output flights. Problem: Only first flight is there, the second is not allocated! */
Here's the function:
short load_flights(flights **flight_list) {
flight_list[0] = calloc(1, sizeof(flights));
flight_list[0]->price = 69;
flight_list[0] = realloc(*flight_list, sizeof(flights)*2);
flight_list[1]->price = 70;
return 2; //num of flights-structs
The problem is, that actually 2 elements should be created, but only 1 element is there - check this debugging screenshot:
As you can see, flight_list[0] is there, but flight_list[1] not! But realloc should do the job?
Am I understanding anything wrong?
There's a bug in this line:
flight_list[1]->price = 70;
Both [] and -> dereference pointers. a[b] is equivalent to *(a+b) and a->b is equivalent to (*a).b. Your line therefore means:
(**(flight_list + 1)).price = 70;
However, flight_list (in load_flights) is a pointer to the flight_list variable in main! In the context of main, you're computing &flight_list + 1, which is an invalid pointer: You're getting the contents of memory that happens to be next to a local variable.
The correct code would be:
(*(*flight_list + 1)).price = 70;
*flight_list is the pointer returned by realloc. Here we can step one element ahead in the dynamic array.
We can also write this as:
(*flight_list)[1].price = 70;
Your flight_list is an array of pointers to pointers of flights.
With flight_list[0] = realloc(*flight_list, sizeof(flights)*2); you allocate space for two flights to the item flight_list[0], but flight_list itself remains unchanged. In fact, there is no code that allocates any space for flight_list at all, but maybe you just left out this code in your example.
If the realloc line of code is what you wanted, you should watch these memory locations in the debugger: flight_list[0][0] for the first flight, and flight_list[0][1] for the second.
I am developing a c program which connects to a mysql database reads data from a a table of 4 million of data and writes its data to another 100 tables in another database after some calculations. To make it efficient I tried to use 100 threads to write data for 100 tables and 1 thread to read data from the database and write those in to a buffer. So that the 100 threads would read from the buffers.
But the problem is when I'm making the buffers. I used malloc to make the buffers. char *** queue; is declared in the header file so that it is global
int i = 0, j = 0;
queue = (char ***) malloc(100);
int threadRet;
for (i; i < 100; i++) {
queue[i] = (char **) malloc(2000);
for (j; j < 2000; j++) {
queue[i][j] = (char *) malloc(180);
}
}
and My buffer writing thread as I mentioned before exicutes the function void * thrededChunkPicker(void * parr)
sprintf(queue[tableNo][marker[tableNo]], "INSERT INTO usage_summary%s(mobile,`0`,ddate) VALUES('%s',%d,'%s') ON DUPLICATE KEY UPDATE `0` = VALUES(`0`), ddate=VALUES(ddate)", row[0] + 7, row[0], sumOfUsage, row[2]);
(marker[tableNo])++;
This is how I write to the buffer . As I've found out the segmentation fault occurs here.
I needed 100 buffers in each of which contains 2000 string arrays of 180. this code compiled successfully.but when runs it gives a segmentation fault.
As far as I can see, all your malloc() calls are problematic.
We pass the size in bytes to malloc(). malloc() does not have any idea of the size of the object in which you're going to store the returned pointer, whatsoever. So, it cannot automatically calculate the total size for the memory required.
We need to calculate the total size required and pass that size to malloc().
First to start with, please see this discussion on why not to cast the return value of malloc() and family in C..
That said, assuming queue is defined as char *** queue;, we need to
queue = malloc(100 * sizeof*queue );
queue[i] = malloc(2000 * sizeof(*queue[i]) );
and so on, if required.
Finally, always check for the success of malloc() through a NULL check on the returned pointer before using the same.
The biggest problem is that malloc allocates a number of bytes, not elements in an array. So you allocate 100 bytes for your three-star variable, which is not enough space for 100 elements. The same with the next call to malloc, it allocates 2000 bytes not 2000 elements.
I've had a look at a few other questions on SO but none of them seem to address a similar problem.
I have a function which sorts an array (using heap sort) and calculates the median. The heap sort routine has been taken directly from Numerical Recipies.
I am callocing and freeing an array inside the median function, but free doesn't seem to be freeing up the space in time. Here's some code to illustrate what I mean :
int calcMedian(int n1, int n2, int *dat)
{
int ii, npt;
int *inparr, retval;
npt = n2 - n1 + 1; /* Number of elements in array */
inparr = calloc(npt+1, sizeof(*inparr));
for(ii = n1; ii <= n2; ii++)
inparr[ii-n1+1] = dat[ii]; /* ii-n1+1 because heapsort function likes arrays to
start from 1 */
heapsortInt(npt, inparr); /* The error isn't here, function has been previously
debugged. Sorting is in-place.*/
if (npt % 2)
retval = inparr[(npt+1)/2];
else
retval = (inparr[npt/2]+inparr[npt/2+1])/2;
free(inparr);
return(retval);
}
The function heapsortInt has been quite thoroughly debugged and has been used in several other places without issue. Now I call my function calcMedian in a loop like so :
for(ii = 0; ii < maxval; ii++) {
index = ii * maxpt;
med1 = calcMedian(index, index+npt1[ii]-1, data1+index);
med2 = calcMedian(index, index+npt2[ii]-1, data2+index);
}
where the relevant variables are defined below :
int *data1, *data2;
int *npt1, *npt2;
data1 = calloc(maxval * maxpt, sizeof(*data1));
data2 = calloc(maxval * maxpt, sizeof(*data2));
npt1 = calloc(maxval, sizeof(*npt1));
npt2 = calloc(maxval, sizeof(*npt2));
So I'm basically passing different sections of one large array into calcMedian and getting back the necessary median values.
THE PROBLEM: calcMedian seems to be crashing when it hits the second function call. I ran it through valgrind, and this is what it told me:
Invalid read of size 4
at 0x43F67E: calcMedian /* Line no. pointing to calloc in calcMedian */
by 0x4416C9: main /* Line no pointing to second call of calcMedian */
Address 0x128ffdc0 is 6,128 bytes inside a block of size 110,788 free'd
at 0x4A063F0: free
by 0x43F728: calcMedian /* Line no. pointing to free in calcMedian */
by 0x4416C9: main /* Line no pointing to first call of calcMedian */
Is this a problem with free? Am I freeing and callocing too frequently? I don't know where to start debugging this. Any help will be wonderful!
DISCLAIMER: The computer with the actual code cannot access the internet. I've reproduced here as accurately as I can the code that causes the problem. If there are any missing semicolons etc. that's my fault, it definitely isn't there in the original code.
Edit: Fixed some transcription errors. I'll try and get the original code up ASAP, but from me looking through both of them now this seems to be fine.
The problem is the call to calcMedian.
You are adding index twice, once in the call, and then inside calcMedian.
It should be like this:
med1 = calcMedian(index, index+npt1[ii]-1, data1);
med2 = calcMedian(index, index+npt2[ii]-1, data2);
This is really strange... and I can't debug it (tried for about two hours, debugger starts going haywire after a while...). Anyway, I'm trying to do something really simple:
Free an array of strings. The array is in the form:
char **myStrings. The array elements are initialized as:
myString[index] = malloc(strlen(word));
myString[index] = word;
and I'm calling a function like this:
free_memory(myStrings, size); where size is the length of the array (I know this is not the problem, I tested it extensively and everything except this function is working).
free_memory looks like this:
void free_memory(char **list, int size) {
for (int i = 0; i < size; i ++) {
free(list[i]);
}
free(list);
}
Now here comes the weird part. if (size> strlen(list[i])) then the program crashes. For example, imagine that I have a list of strings that looks something like this:
myStrings[0] = "Some";
myStrings[1] = "random";
myStrings[2] = "strings";
And thus the length of this array is 3.
If I pass this to my free_memory function, strlen(myStrings[0]) > 3 (4 > 3), and the program crashes.
However, if I change myStrings[0] to be "So" instead, then strlen(myStrings[0]) < 3 (2 < 3) and the program does not crash.
So it seems to me that free(list[i]) is actually going through the char[] that is at that location and trying to free each character, which I imagine is undefined behavior.
The only reason I say this is because I can play around with the size of the first element of myStrings and make the program crash whenever I feel like it, so I'm assuming that this is the problem area.
Note: I did try to debug this by stepping through the function that calls free_memory, noting any weird values and such, but the moment I step into the free_memory function, the debugger crashes, so I'm not really sure what is going on. Nothing is out of the ordinary until I enter the function, then the world explodes.
Another note: I also posted the shortened version of the source for this program (not too long; Pastebin) here. I am compiling on MinGW with the c99 flag on.
PS - I just thought of this. I am indeed passing numUniqueWords to the free function, and I know that this does not actually free the entire piece of memory that I allocated. I've called it both ways, that's not the issue. And I left it how I did because that is the way that I will be calling it after I get it to work in the first place, I need to revise some of my logic in that function.
Source, as per request (on-site):
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "words.h"
int getNumUniqueWords(char text[], int size);
int main(int argc, char* argv[]) {
setvbuf(stdout, NULL, 4, _IONBF); // For Eclipse... stupid bug. --> does NOT affect the program, just the output to console!
int nbr_words;
char text[] = "Some - \"text, a stdin\". We'll have! also repeat? We'll also have a repeat!";
int length = sizeof(text);
nbr_words = getNumUniqueWords(text, length);
return 0;
}
void free_memory(char **list, int size) {
for (int i = 0; i < size; i ++) {
// You can see that printing the values is fine, as long as free is not called.
// When free is called, the program will crash if (size > strlen(list[i]))
//printf("Wanna free value %d w/len of %d: %s\n", i, strlen(list[i]), list[i]);
free(list[i]);
}
free(list);
}
int getNumUniqueWords(char text[], int length) {
int numTotalWords = 0;
char *word;
printf("Length: %d characters\n", length);
char totalWords[length];
strcpy(totalWords, text);
word = strtok(totalWords, " ,.-!?()\"0123456789");
while (word != NULL) {
numTotalWords ++;
printf("%s\n", word);
word = strtok(NULL, " ,.-!?()\"0123456789");
}
printf("Looks like we counted %d total words\n\n", numTotalWords);
char *uniqueWords[numTotalWords];
char *tempWord;
int wordAlreadyExists = 0;
int numUniqueWords = 0;
char totalWordsCopy[length];
strcpy(totalWordsCopy, text);
for (int i = 0; i < numTotalWords; i++) {
uniqueWords[i] = NULL;
}
// Tokenize until all the text is consumed.
word = strtok(totalWordsCopy, " ,.-!?()\"0123456789");
while (word != NULL) {
// Look through the word list for the current token.
for (int j = 0; j < numTotalWords; j ++) {
// Just for clarity, no real meaning.
tempWord = uniqueWords[j];
// The word list is either empty or the current token is not in the list.
if (tempWord == NULL) {
break;
}
//printf("Comparing (%s) with (%s)\n", tempWord, word);
// If the current token is the same as the current element in the word list, mark and break
if (strcmp(tempWord, word) == 0) {
printf("\nDuplicate: (%s)\n\n", word);
wordAlreadyExists = 1;
break;
}
}
// Word does not exist, add it to the array.
if (!wordAlreadyExists) {
uniqueWords[numUniqueWords] = malloc(strlen(word));
uniqueWords[numUniqueWords] = word;
numUniqueWords ++;
printf("Unique: %s\n", word);
}
// Reset flags and continue.
wordAlreadyExists = 0;
word = strtok(NULL, " ,.-!?()\"0123456789");
}
// Print out the array just for funsies - make sure it's working properly.
for (int x = 0; x <numUniqueWords; x++) {
printf("Unique list %d: %s\n", x, uniqueWords[x]);
}
printf("\nNumber of unique words: %d\n\n", numUniqueWords);
// Right below is where things start to suck.
free_memory(uniqueWords, numUniqueWords);
return numUniqueWords;
}
You've got an answer to this question, so let me instead answer a different question:
I had multiple easy-to-make mistakes -- allocating a wrong-sized buffer and freeing non-malloc'd memory. I debugged it for hours and got nowhere. How could I have spent that time more effectively?
You could have spent those hours writing your own memory allocators that would find the bug automatically.
When I was writing a lot of C and C++ code I made helper methods for my program that turned all mallocs and frees into calls that did more than just allocate memory. (Note that methods like strdup are malloc in disguise.) If the user asked for, say, 32 bytes, then my helper method would add 24 to that and actually allocate 56 bytes. (This was on a system with 4-byte integers and pointers.) I kept a static counter and a static head and tail of a doubly-linked list. I would then fill in the memory I allocated as follows:
Bytes 0-3: the counter
Bytes 4-7: the prev pointer of a doubly-linked list
Bytes 8-11: the next pointer of a doubly-linked list
Bytes 12-15: The size that was actually passed in to the allocator
Bytes 16-19: 01 23 45 67
Bytes 20-51: 33 33 33 33 33 33 ...
Bytes 52-55: 89 AB CD EF
And return a pointer to byte 20.
The free code would take the pointer passed in and subtract four, and verify that bytes 16-19 were still 01 23 45 67. If they were not then either you are freeing a block you did not allocate with this allocator, or you've written before the pointer somehow. Either way, it would assert.
If that check succeeded then it would go back four more and read the size. Now we know where the end of the block is and we can verify that bytes 52 through 55 are still 89 AB CD EF. If they are not then you are writing over the end of a block somewhere. Again, assert.
Now that we know that the block is not corrupt we remove it from the linked list, set ALL the memory of the block to CC CC CC CC ... and free the block. We use CC because that is the "break into the debugger" instruction on x86. If somehow we end up with the instruction pointer pointing into such a block it is nice if it breaks!
If there is a problem then you also know which allocation it was, because you have the allocation count in the block.
Now we have a system that finds your bugs for you. In the release version of your product, simply turn it off so that your allocator just calls malloc normally.
Moreover you can use this system to find other bugs. If for example you believe that you've got a memory leak somewhere all you have to do is look at the linked list; you have a complete list of all the outstanding allocations and can figure out which ones are being kept around unnecessarily. If you think you're allocating too much memory for a given block then you can have your free code check to see if there are a lot of 33 in the block that is about to be freed; that's a sign that you're allocating your blocks too big. And so on.
And finally: this is just a starting point. When I was using this debug allocator professionally I extended it so that it was threadsafe, so that it could tell me what kind of allocator was doing the allocation (malloc, strdup, new, IMalloc, etc.), whether there was a mismatch between the alloc and free functions, what source file contained the allocation, what the call stack was at the time of the allocation, what the average, minimum and maximum block sizes were, what subsystems were responsible for what memory usage...
C requires that you manage your own memory; this definitely has its pros and cons. My opinion is that the cons outweigh the pros; I much prefer to work in automatic storage languages. But the nice thing about having to manage your own storage is that you are free to build a storage management system that meets your needs, and that includes your debugging needs. If you must use a language that requires you to manage storage, use that power to your advantage and build a really powerful subsystem that you can use to solve professional-grade problems.
The problem is not how you're freeing, but how you're creating the array. Consider this:
uniqueWords[numUniqueWords] = malloc(strlen(word));
uniqueWords[numUniqueWords] = word;
...
word = strtok(NULL, " ,.-!?()\"0123456789");
There are several issues here:
word = strtok(): what strtok returns is not something that you can free, because it has not been malloc'ed. ie it is not a copy, it just points to somewhere inside the underlying large string (the thing you called strtok with first).
uniqueWords[numUniqueWords] = word: this is not a copy; it just assigns the pointer. the pointer which is there before (which you malloc'ed) is overwritten.
malloc(strlen(word)): this allocates too little memory, should be strlen(word)+1
How to fix:
Option A: copy properly
// no malloc
uniqueWords[numUniqueWords] = strdup(word); // what strdup returns can be free'd
Option B: copy properly, slightly more verbose
uniqueWords[numUniqueWords] = malloc(strlen(word)+1);
strcpy(uniqueWords[numUniqueWords], word); // use the malloc'ed memory to copy to
Option C: don't copy, don't free
// no malloc
uniqueWords[numUniqueWords] = word; // not a copy, this still points to the big string
// don't free this, ie don't free(list[i]) in free_memory
EDIT As other have pointed out, this is also problematic:
char *uniqueWords[numTotalWords];
I believe this is a GNU99 extension (not even C99), and indeed you cannot (should not) free it. Try char **uniqueWords = (char**)malloc(sizeof(char*) * numTotalWords). Again the problem is not the free() but the way you allocate. You are on the right track with the free, just need to match every free with a malloc, or with something that says it is equivalent to a malloc (like strdup).
You are using this code in an attempt to allocate the memory:
uniqueWords[numUniqueWords] = malloc(strlen(word));
uniqueWords[numUniqueWords] = word;
numUniqueWords++;
This is wrong on many levels.
You need to allocate strlen(word)+1 bytes of memory.
You need to strcpy() the string over the allocated memory; at the moment, you simply throw the allocated memory away.
Your array uniqueWords is itself not allocated, and the word values you have stored are from the original string which has been mutilated by strtok().
As it stands, you cannot free any memory because you've already lost the pointers to the memory that was allocated and the memory you are trying to free was never in fact allocated by malloc() et al.
And you should be error checking the memory allocations too. Consider using strdup() to duplicate strings.
You are trying to free char *uniqueWords[numTotalWords];, which is not allowed in C.
Since uniqueWords is allocated on the stack and you can't call free on stack memory.
Just remove the last free call, like this:
void free_memory(char **list, int size) {
for (int i = 0; i < size; i ++) {
free(list[i]);
}
}
Proper way of allocating and deallocating char array.
char **foo = (char **) malloc(row* sizeof(char *));
*foo = malloc(row * col * sizeof(char));
for (int i = 1; i < row; i++) {
foo[i] = *foo + i*col;
}
free(*foo);
free(foo);
Note that you don't need to go through each & every element of the array for deallocation of memory. Arrays are contiguous so call free on the name of the array.
here is a very small structure used for indexing words of a file. Its members are a string (the word), an array of integers (the lines this word is found at), and an integer representing the index of the first free cell in the lines array.
typedef struct {
wchar_t * word;
int * lines;
int nLine;
} ndex;
ndex * words;
I am trying to allocate (ndex)es nb_words = 128 at a time, and (lines) nb_lines = 8 at a time, using malloc and realloc.
First question, what is the difference between malloc(number * size) and calloc(number, size) when allocating *words and/or *lines? Which should I choose?
Second question, I gdbed this:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400cb0 in add_line (x=43, line=3) at cx17.3.c:124
124 words[x].lines[words[x].nLine] = line;
(gdb) p words[43].nLine
$30 = 0
In other words, it consistently fails at
words[43].lines[0] = 3;
Since I allocate words by 128, and lines by 8, there is no reason the indexing worked for the 42 previous words and fail here, except if my allocating was botched, is there?
Third question: here are my allocations, what is wrong with them?
words = malloc(sizeof(ndex *) * nb_words);
short i;
for (i = 0; i < nb_words; i++) {
words[i].lines = malloc(sizeof(int) * nb_lines);
words[i].nLine = 0;
}
Should I initialize lines in a for(j) loop? I don't see why leaving it uninitialized would prevent writing to it, so long as it as been allocated.
This C is a very mysterious thing to me, thanks in advance for any hints you can provide.
Best regards.
This looks suspicious:
sizeof(ndex *)
You probably don't want the size of a pointer - you want the size of a structure. So remove the star.
Here:
words = malloc(sizeof(ndex *) * nb_words);
You are allocating space for some number of pointers (i.e., 4 bytes * nb_words). What you really need is to allocate some number of ndex's:
words = malloc(sizeof(ndex) * nb_words);
Also, calloc 0 initializes the returned buffer while malloc does not. See this answer.
malloc will allocate the requested space only. calloc will allocate the space and initialize to zero.
In your example, the segmentation fault is observed here words[x].lines[words[x].nLine] = line;. There could be 2 possibilities viz., allocation is wrong which I don't feel is the case. The more probable case would be words[x].nLine didn't evaluate to 0. Please print this value and check. I suspect this is some huge number which is forcing your program to access a memory out of your allocated space.
Others have answered this part, so I will skip it.