Dynamic array allocation - valgrind conditional jump - c

I am trying to read a line from stdin in C and at the same time dynamically allocate memory for the string using the code snippet from below. The problem is that when I run this code, calling something like strlen(msg) results in an Conditional jump or move depends on uninitialised value(s) in valgrinds output.
I don't understand how to get past this problem because I can't properly initialize it if I am dynamically allocating it. I've spent a really long time on this now and can't seem to figure it out... any help would be much appreciated.
char* msg = NULL;
int c;
// set initial size for dynamic allocation
msg = malloc(sizeof(char)*10+1);
int idx = 0;
char* temp = NULL;
size_t size = 10;
while (1){
c = getchar();
if(c == EOF || c == '\n'){
break;
}else if(!isalpha(c)){
free(msg);
exit(100);
}
// dynamically reallocate memory if input too large
if(size <= idx){
size += size;
temp = realloc(msg, size);
msg = temp;
}
msg[idx++] = (char)c;
}
printf("%ld", strlen(msg));

You never terminate the string you create in msg.
After the loop (but before you use msg as a null-terminated string with e.g. strlen(msg)) add the terminator:
msg[idx] = '\0';
There's another problem though, which might crop up unexpectedly: When you reallocate the memory you don't add space for the terminator.
Use-case for this problem: You enter a string with exactly 20 characters.
You will then have reallocated once, making the size exactly 20 bytes (characters). The last character will be put at index 19, then idx is increased to 20 (which is out of bounds). Next iteration of the loop you detect the newline, and break out, and will then set the terminator on the 21:st character in your 20-character array.
Add 1 to the size when calling realloc to solve this:
temp = realloc(msg, size + 1);

Related

Segmentation fault strcat

I got a problem when reading SSL response that causes a segmentation fault. I read the response into a buffer, then append it to a malloced string and memory reset it to 0 till the response is fully read, but when I try this in a multi threaded program, after some operations it gives me segmentation fault. When I remove strcat it doesn't give me segmentation fault even if I run it for hours.
Example:
char* response = malloc(10000);
char buffer[10000] = { 0 };
while(SSL_read(ssl,buf,sizeof(buffer)) > 0){
strcat(response,buffer);
memset(buffer,0,sizeof(buffer));
}
Errors
free(): invalid next size (normal)
malloc_consolidate(): invalid chunk
I made sure of freeing both of SSL and CTX and close socket and free the malloced string.
There are a few problems with your code:
You are not dealing with C strings, you are dealing with arbitrary byte sequences. SSL_read() reads bytes, not C strings, and you cannot treat them as strings. What you read cannot be assumed to be NUL-terminated (\0), so you should not use strcat, strlen or other similar functions that operate on strings. Zeroing out the entire buffers just to make sure there is a terminator makes little to no sense, as the terminator could very well be found in the middle of the data.
You are reading data continuously in a loop into a fixed size buffer. Your code will overflow the destination buffer (response) very easily.
Not an error, but there isn't really any need for an intermediate buffer to begin with. You are needlessly copying stuff around two times (one with SSL_read() and one with strcat) when you can read directly into response instead. On top of that, the memset() to clear the contents of buffer also adds a third scan of the data, slowing things down even more.
Again, not an error, but SSL_read() returns int and uses that to return the read size. You are not really using it, but you should, as you need to keep track of how much space is left on the buffer. You would be however much better off using size_t to avoid unwanted problems with signed math and possible overflows. You can use SSL_read_ex() for this purpose.
Here's a snippet of code that does what you want in a more robust way:
#define CHUNK_SIZE 10000
unsigned char *response = NULL;
size_t size = 0;
size_t space_left = 0;
size_t total_read = 0;
size_t n;
while (1) {
// Allocate more memory if needed.
if (space_left < CHUNK_SIZE) {
unsigned char *tmp = realloc(response, size + CHUNK_SIZE);
if (!tmp) {
// Handle realloc error
break;
}
response = tmp;
size += CHUNK_SIZE;
space_left += CHUNK_SIZE;
}
if (SSL_read_ex(ssl, response + total_read, space_left, &n)) {
total_read += n;
space_left -= n;
} else {
// Handle error
break;
}
}
You never initialized response(). The arguments to strcat() have to be null-terminated strings.
You should also subtract 1 from the size of the buffer when calling SSL_read(), to ensure there will always be room for its null terminator.
char* response = malloc(10000);
response[0] = '\0';
char buffer[10000] = { 0 };
while(SSL_read(ssl,buf,sizeof(buffer)-1) > 0){
strcat(response,buffer);
memset(buffer,0,sizeof(buffer));
}

String input function using dynamic memory allocation breaks after random amount of characters

I'm terrible at life, so it's possible my function itself is just broken beyond repair. The function takes user input using getchar(), dynamically reallocates memory per-character with realloc() (and I'm sure that's probably innefficient as hell but I'm not sure how else to keep it memory efficient) and returns a full string as a char pointer. Here's the code:
char *get_string_input(){
char c, *str = NULL;
int i = 0;
// allocate initial space for a single character
str = malloc(sizeof(char));
while(c != '\n' && c != EOF){
c = getchar();
str[i++] = c;
// reallocate with space for +1 additional character
str = realloc(str, i * sizeof(char));
}
str[i] = '\0';
return str;
}
If a certain amount of characters are entered (between 7 - 9 usually) the program will crash. I have no idea where the issue lies, and it's happening with pretty much anything I try and type.
Help much appreciated, thank you!

Dynamic 2D array crashes

I am reading from a file (each line wolds 1 word) and putting each line into an array. It crashes when its about to close the file saying (* glibc detected * proj: corrupted double-linked list: 0x0000000002139240 ***). Also everything but the 1st element was copied correctly (the 1st element was supposed to be "how are you" but was instead "0"). Any help on this is greatly appreciated.
int i = -1;
int numb;
int wsize;
while (fgets(word,30,file)!=NULL)
{
if (i==-1)
{
if(word[strlen(word)-1]=='\n')
{
word[strlen(word)-1] = 0;
}
numb = atoi(word);
ptr = malloc(sizeof(char*)*numb);
}
else
{
if(word[strlen(word)-1]=='\n')
{
word[strlen(word)-1] = 0;
}
wsize = strlen(word);
ptr[i] = malloc(sizeof(char*)*wsize);
strncpy(ptr[i],word,strlen(word));
size++;
}
i++;
}
int j=0;
while(j<16) //prints to see if they were copied corectly
{ //ptr[0] was the only one that did not copy corectly
printf("%s\n",ptr[j]);
j++;
}
fclose(file);
printf("test\n"); //was never printed so I assume it crashes at fclose()
return 1;
The line ptr[i] = malloc(sizeof(char*)*wsize); is wrong, for two reasons:
It should be sizeof(char), not sizeof(char*) (or just omit this, since sizeof(char) is equal to 1 by definition)
If you want to store a string of length wsize, you need to allocate wsize+1 bytes
EDIT — More issues:
What is the purpose of the line size++;? Did you mean wsize++;?
Where does the number 16 come from in while(j<16)? I suggest you try while(j<i) instead.
If main() returns a nonzero value, this signifies that an error occurred. Change this to return 0; unless you have a good reason for returning some other value.
One more:
I just noticed you're using strncpy(). This won't add a terminating '\0' byte to the end of the string because you've asked it to copy a string of length wsize using no more than wsize bytes. Change this line to strcpy(ptr[i],word); and it should work.
After you've done that, you need to remove all the potential buffer overflows from your code. (There are lots of them.)

Array Not Filling Properly

I am trying to deconstruct a document into its respective paragraphs, and input each paragraphs, as a string, into an array. However, each time a new value is added, it overwrites all previous values in the array. The last "paragraph" read (as denoted by newline) is the value of each non-null value of the array.
Here is the code:
char buffer[MAX_SIZE];
char **paragraphs = (char**)malloc(MAX_SIZE * sizeof(char*));
int pp = 0;
int i;
FILE *doc;
doc = fopen(argv[1], "r+");
assert(doc);
while((i = fgets(buffer, sizeof(buffer), doc) != NULL)) {
if(strncmp(buffer, "\n", sizeof(buffer))) {
paragraphs[pp++] = (char*)buffer;
}
}
printf("pp: %d\n", pp);
for(i = 0; i < MAX_SIZE && paragraphs[i] != NULL; i++) {
printf("paragraphs[%d]: %s", i, paragraphs[i]);
}
The output I receive is:
pp: 4
paragraphs[0]: paragraph four
paragraphs[1]: paragraph four
paragraphs[2]: paragraph four
paragraphs[3]: paragraph four
when the program is run as follows: ./prog.out doc.txt, where doc.txt is:
paragraph one
paragraph two
paragraph three
paragraph four
The behavior of the program is otherwise desired. The paragraph count works properly, ignoring the line that contains ONLY the newline character (line 4).
I assume the problem occurs in the while loop, however am unsure how to remedy the problem.
Your solution is pretty sound. Your Paragraph array is supposed to hold each paragraph, and since each paragraph element is just a small 4 bytes pointer you can afford to define a reasonable max number of them. However, since this max number is a constant, it is of little use to allocate the array dynamically.
The only meaningful use of dynamic allocation would be to read the whole text once to count the actual number of paragraphs, allocate the array accordingly and re-read the whole file a second time, but I doubt this is worth the effort.
The downside of using fixed-size paragraph array is that you must stop filling it once you reach the maximal number of elements.
You can then re-allocate a bigger array if you absolutely want to be able to process the whole Bible, but for an educational exercise I think it's reasonable to just stop recording paragraphs (thus producing a code that can store and count paragraphs up to a maximal number).
The real trouble with your code is, you don't store the paragraph contents anywhere. When you read the actual lines, it's always inside the same buffer, so each paragraph will point to the same string, which will contain the last paragraph read.
The solution is to make a unique copy of the buffer and have the current paragraph point to that.
C being already messy enough as it is, I suggest using the strdup() function, which duplicates a string (basically computing string length, allocating sufficient memory, copying the string into it and returning the new block of memory holding the new copy). You just need to remember to free this new copy once you're done using it (in your case at the end of your program).
This is not the most time-efficient solution, since each string will require a strlen and a malloc performed internally by strdump while you could have pre-allocated a big buffer for all paragraphs, but it is certainly simpler and probably more memory-efficient (only the minimal amount of memory will be allocated for each string, though each malloc consumes a few extra bytes for internal allocator housekeeping).
The bloody awkward fgets also stores the trailing \n at the end of the line, so you'll probably want to get rid of that.
Your last display loop would be simpler, more robust and more efficient if you simply used pp as a limit, instead of checking uninitialized paragraphs.
Lastly, you'd better define two different constants for max line size and max number of paragraphs. Using the same value for both makes little sense, unless you're processing perfectly square texts :).
#define MAX_LINE_SIZE 82 // max nr of characters in a line (including trailing \n and \0)
#define MAX_PARAGRAPHS 100 // max number of paragraphs in a file
void main (void)
{
char buffer[MAX_LINE_SIZE];
char * paragraphs[MAX_PARAGRAPHS];
int pp = 0;
int i;
FILE *doc;
doc = fopen(argv[1], "r+");
assert(doc != NULL);
while((fgets(buffer, sizeof(buffer), doc) != NULL)) {
if (pp != MAX_PARAGRAPHS // make sure we don't overflow our paragraphs array
&& strcmp(buffer, "\n")) {
// fgets awkwardly collects the ending \n, so get rid of it
if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0';
// current paragraph references a unique copy of the actual text
paragraphs[pp++] = strdup (buffer);
}
}
printf("pp: %d\n", pp);
for(i = 0; i != pp; i++) {
printf("paragraphs[%d]: %s", i, paragraphs[i]);
free(paragraphs[i]); // release memory allocated by strdup
}
}
What is the proper way to allocate the necessary memory? Is the malloc on line 2 not enough?
No, you need to allocate memory for the 2D array of strings you created. The following will not work as coded.
char **paragraphs = (char**)malloc(MAX_SIZE * sizeof(char*));
If you have: (for a simple explanation)
char **array = {0}; //array of C strings, before memory is allocation
Then you can create memory for it like this:
int main(void)
{
int numStrings = 10;// for example, change as necessary
int maxLen = MAX_SIZE; //for example, change as necessary
char **array {0};
array = allocMemory(array, numStrings, maxLen);
//use the array, then free it
freeMemory(array, numStrings);
return 0;
}
char ** allocMemory(char ** a, int numStrings, int maxStrLen)
{
int i;
a = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(sizeof(char)*maxStrLen + 1, sizeof(char));
}
return a;
}
void freeMemory(char ** a, int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(a[i]) free(a[i]);
free(a);
}
Note: you can determine the number of lines in a file several ways, One way for example, by FILE *fp = fopen(filepath, "r");, then calling ret = fgets(lineBuf, lineLen, fp) in a loop until ret == EOF, keeping count of an index value for each loop. Then fclose(). (which you did not do either) This necessary step is not included in the code example above, but you can add it if that is the approach you want to use.
Once you have memory allocated, Change the following in your code:
paragraphs[pp++] = (char*)buffer;
To:
strcpy(paragraphs[pp++], buffer);//no need to cast buffer, it is already char *
Also, do not forget to call fclose() when you are finished with the open file.

Opening a file with path in malloc

I'm trying to open a file with fopen, but I don't want a static location so I am getting the string in from the user when he/she runs the program.
However if a user does not enter one a default file is specified.
Can I just put the malloc var in to the fopen path parameter?
char *file_path_mem = malloc(sizeof(char));
if (file_path_mem != NULL) //Null if out of memory
{
printf("Enter path to file, if in current directory then specify name\n");
printf("File(default: marks.txt): ");
while ((c = (char)getchar()) != '\n')
{
file_path_mem[i++] = c;
file_path_mem = realloc(file_path_mem, i+1 * sizeof(char));
}
file_path_mem[i] = '\0';
if (i == 0 && c == '\n')
{
file_path_mem = realloc(file_path_mem, 10 * sizeof(char);
file_path_mem = "marks.txt";
}
}
else
{
printf("Error: Your system is out of memory, please correct this");
return 0;
}
if (i==0)
{
FILE *marks_file = fopen("marks.txt", "r");
}
else
{
FILE *marks_file = fopen(file_path_mem, "r");
}
free(file_path_mem);
As you might have guess I am a c novice so if I have done something horrible wrong, then sorry.
This is not doing what you think it is:
file_path_mem = realloc(file_path_mem, 10 * sizeof(char);
file_path_mem = "marks.txt";
What you want to do is change that second line to copy the default name into the allocated buffer:
strcpy(file_path_mem, "marks.txt");
You CAN pas the char* returned from malloc straight into fopen. Just make sure it contains valid data. Though make sure you strcpy the new string in as R Samuel points out.
Btw, your use of realloc will give pretty awful performance. Realloc works by seeing if there is enogh space to grow the memory (This is not guranteed, realloc must just return a block that is the newSize containing the old data). If there isn't enough space, it allocs a new block of the new size and copies the old data ot the new block. Obviously this is suboptimal.
You are better off allocating a block of, say, 16 chars and then , if you need more than 16, realloc'ing a further 16 chars. There will be a bit of memory wastage but you are not, potentially, copying anything like as much memory around.
Edit: Further to that. For a string that contains 7 character. Using your realloc every byte scheme you will generate the following processes.
alloc 1 byte
alloc 2 bytes
copy 1 byte
free 1 byte
alloc 3 bytes
copy 2 bytes
free 2 bytes
alloc 4 bytes
copy 3 bytes
free 3 bytes
alloc 5 bytes
copy 4 bytes
free 4 bytes
alloc 6 bytes
copy 5 bytes
free 5 bytes
alloc 7 bytes
copy 6 bytes
free 6 bytes
alloc 8 bytes
copy 7 bytes
This is 8 allocations, 7 frees and a copy of 28 bytes. Not to mention the 8 bytes you assign to the array (7 characters + 1 null terminator).
Allocations are SLOW. Frees are SLOW. Copying is much slower than not copying.
For this example using my allocate 16 bytes at a time system you alloc once, assign 8 bytes. No copies and the only free is when you've finished with it. You DO waste 8 bytes though. But ... well ... 8 bytes is nothing in the grand scheme of things...
realloc is relatively more expensive than the rest of your loop, so you might as well just start with a 128 byte buffer, and realloc another 128 bytes if you fill that up.
I suggest some of the following changes:
define your default location at the top of the file
char* defaultLocation = 'myfile.txt';
char* locationToUse;
use constants instead of hard coding numbers in your code (like the 10 you have in there)
int DEFAULT_INPUT_BUFFER_SIZE = 128;
char* userInputBuffer = malloc(sizeof(char) * DEFAULT_INPUT_BUFFER_SIZE) );
int bufferFillIndex = 0;
only reallocate infrequently, and not at all if possible (size 128 buffer)
while ((c = (char)getchar()) != '\n')
{
file_path_mem[bufferFillIndex++] = c;
if (bufferFillIndex % DEFAULT_INPUT_BUFFER_SIZE == 0)
{
realloc(file_path_mem, (bufferFillIndex + DEFAULT_INPUT_BUFFER_SIZE) * sizeof(char);
}
}
Should not be an issue here but for realocation you should state the new size like that
file_path_mem = realloc(file_path_mem, (i+1) * sizeof(char));
You could simplify this greatly with getline(), assuming it is available on your system:
printf("Enter path to file, if in current directory then specify name\n");
printf("File(default: marks.txt): ");
int bufSize = 100;
char* fileNameBuf = (char*) malloc(bufSize + 1);
int fileNameLength = getline(&fileNameBuf, &bufSize, stdin);
if(fileNameLength < 0)
{
fprintf(stderr, "Error: Not enough memory.\n")
exit(1);
}
/* strip line end and trailing whitespace. */
while(fileNameLength && fileNameBuf[fileNameLength - 1] <= ' ')
--fileNameLength;
fileNameBuf[fileNameLength] = 0;
if(!fileNameLength)
{
free(fileNameBuf); /* Nothing entered; use default. */
fileNameBuf = "marks.txt";
}
FILE *marks_file = fopen(fileNameBuf, "r");
if(fileNameLength)
free(fileNameBuf);
I don't know if your C supports in-block declarations, so I'll let you fix that if needed.
EDIT: Here's a getline tutorial.
As a learning experience I would second the suggestions of others to expand your buffer by more than one byte. It won't make any difference if it's not in a loop but calling realloc() on each byte would be unacceptable in other contexts.
One trick that works fairly well is to double the size of the buffer every time it fills up.
On the other hand, if you really just want to open a file and don't care about writing the world's greatest name loop, then standard procedure is to simplify the code even at the price of a limit on file name length. There is no rule that says you have to accept silly pathnames.
FILE *read_and_open(void)
{
char *s, space[1000];
printf("Enter path to file, if in current directory then specify name\n");
printf("File(default: marks.txt): ");
fgets(space, sizeof space, stdin);
if((s = strchr(space, '\n')) != NULL)
*s = 0;
if (strlen(space) == 0)
return fopen("marks.txt", "r");
return fopen(space, "r");
}

Resources