Considering the toy-code as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH (5000)
typedef struct request_body_s {
char *data;
size_t size; // in bytes
} request_body_t;
int do_something(request_body_t *request_body) {
char* content = read_content_elsewhere("/dir/content");
size_t size = strlen(content) * sizeof(char);
request_body->data = (char *) realloc(request_body->data, size + 1);
if (request_body->data == NULL)
return 0;
else {
request_body->size = size;
strncpy(request_body->data, content, MAX_STRING_LENGTH);
return 1;
}
}
int main(int argc, char *argv[]) {
request_body_t request_body;
request_body.data = malloc(1);
request_body.size = 0;
if (do_something(&request_body))
printf("Read!\n");
else {
printf("Error!\n");
exit(0);
}
free(request_body.data);
request_body.size = 0;
}
This code seems work fine until free(request_body.data) is called; it generates an error as follows:
*** free(): invalid next size (fast): 0x0000000001594570 ***
What is (of course) wrong and why? Thanks for any suggestion.
I believe the issue is right here:
strncpy(request_body->data, content, MAX_STRING_LENGTH);
depending on your goal (not clear from your description), I would suggest:
strncpy(request_body->data, content, size > MAX_STRING_LENGTH ? MAX_STRING_LENGTH : size );
strncpy copies the first n chars of the string, that is 5000 in your case. If the source string is smaller that n (5000 here), the rest is padded with zeros, therefore you are accessing further that the end of your bufffer, which leads to undefined behaviour.
You need:
strcpy(request_body->data, content);
It is safe here to use strcpy because we can be sure that the memory allocated by realloc is large enough, because you realloc strlen(content) + 1 chars.
BTW * sizeof(char) is always 1 by definition, so the * sizeof(char) is not necessary.
As written in the strncpy manual,
If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.
So, by using strncpy(request_body->data, content, 5000);, you write many '\0' outside your buffer. You shouldn't ever do that, it's an undefined behaviour, and, in this case, you're writing on the 'metadata' used by free, so it crashes.
Here, it would be preferable to use strcpy (and make sure to add a '\0' at the end), or memcpy, because you know the size you want to write.
Also, casting the return of malloc is useless, and sizeof(char) is and will very probably always be 1, so it's also useless.
Related
I am studying for a Data Structures and Algorithms exam. One of the sample questions related to dynamic memory allocation requires you to create a function that passes a string, which takes it at copies it to a user defined char pointer. The question provides the struct body to start off.
I did something like this:
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string* create_smart_string(char *str)
{
smart_string *s = (smart_string*)malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(s->length);
strcpy(s->word, str);
return s;
}
But the answer was this
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string *create_smart_string(char *str)
{
smart_string *s = malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(sizeof(char) * (s->length + 1));
strcpy(s->word, str);
return s;
}
I went on code:blocks and tested them both to see any major differences. As far as I'm aware, their outputs were the same.
I did my code the way it is because I figured if we were to allocate a specific block of memory to s->word, then it should be the same number of bytes as s ->length, because that's the string we want to copy.
However the correct answer below multiplies sizeof(char) (which is just 1 byte), with s->length + 1. Why the need to add 1 to s->length? What's the importance of multiplying s->length by sizeof(char)? What mistakes did I make in my answer that I should look out for?
sizeof(char) == 1 by definition, so that doesn't matter.
You should not cast the result of malloc: Do I cast the result of malloc?
And your only real difference is that strlen returns the length of the string, not including the terminating NUL ('\0') character, so you need to add + 1 to the size of the buffer as in the solution.
If you copy there the string, the terminating character won't be copied (or worse, it will be copied on some other memory), and therefore, any function that deals with strings (unless you use special safety functions such as strscpy) will run through the buffer and past it since they won't find the end. At that point it is undefined behaviour and everything can happen, even working as expected, but can't rely on that.
The reason it is working as expected is because probably the memory just next to the buffer will be 0 and therefore it is being interpreted as the terminating character.
Your answer is incorrect because it doesn't account for the terminating '\0'-character. In C strings are terminated by 0. That's how their length can be determined. A typical implementation of strlen() would look like
size_t strlen(char const *str)
{
for (char const *p = str; *p; ++p); // as long as p doesn't point to 0 increment p
return p - str; // the length of the string is determined by the distance of
} // the '\0'-character to the beginning of the string.
But both "solutions" are fubar, though. Why would one allocate a structure consisting of an int and a pointer on the free-store ("heap")!? smart_string::length being an int is the other wtf.
#include <stddef.h> // size_t
typedef struct smart_string_tag { // *)
char *word;
size_t length;
} smart_string_t;
#include <assert.h> // assert()
#include <string.h> // strlen(), strcpy()
#include <stdlib.h> // malloc()
smart_string_t create_smart_string(char const *str)
{
assert(str); // make sure str isn't NULL
smart_string_t new_smart_string;
new_smart_string.length = strlen(str);
new_smart_string.word = calloc(new_smart_string.length + 1, sizeof *new_smart_string.word);
if(!new_smart_string.word) {
new_smart_string.length = 0;
return new_smart_string;
}
strcpy(new_smart_string.word, str);
return new_smart_string;
}
*) Understanding C Namespaces
I thought I understood the answer to this question but I don't. I understand the first result but I still don't know how to do the copy correctly. I tried the following code:
// TstStrArr.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <malloc.h>
int main()
{
char ** StrPtrArr;
char InpBuf0[] = "TstFld0";
char InpBuf1[] = "TstFld1";
StrPtrArr = (char **)malloc(2 * sizeof(char *));
StrPtrArr[0] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf0, sizeof(StrPtrArr[0]));
strncpy_s(StrPtrArr[0], sizeof(StrPtrArr[0]), InpBuf0, _TRUNCATE);
printf("strptrarr=%s\n", StrPtrArr[0]);
StrPtrArr[1] = (char *)malloc(10 + 1);
printf("inpbuf=%s sizeof=%2d ", InpBuf1, sizeof(*StrPtrArr[1]));
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE); // error here
printf("*strptrarr=%s\n", StrPtrArr[1]);
free(StrPtrArr[0]);
free(StrPtrArr[1]);
free(StrPtrArr);
return 0;
}
The result I got was:
inpbuf=TstFld0 sizeof= 4 strptrarr=Tst
inpbuf=TstFld1 sizeof= 1
and the following error:
Exception thrown: write access violation.
destination_it was 0xFFFFFFCD.
The result I thought I'd get was either of the following:
inpbuf=TstFld1 sizeof=11 *strptrarr=TstFld1
inpbuf=TstFld1 sizeof= 1 *strptrarr=T
I understand the first copy copied the input buffer to the 4 byte pointer which was incorrect. I thought the second copy would copy the input buffer to the value of the dereferenced pointer of a size of 11 but it didn't. I'm guessing the copy was to the first character of the string in the array. I don't understand memory enough to know the significance of the address 0xFFFFFFCD but I guess it's in read-only memory thus causing the error.
What is the correct way to do the copy?
(I don't think it matters, but I'm using VS 2015 Community Edition Update 3.)
Why
strncpy_s(*StrPtrArr[1], sizeof(*StrPtrArr[1]), InpBuf1, _TRUNCATE);
?
*StrPtrArr[1] should be StrPtrArr[1] because StrPtrArr is of type char** and you need char* here.
and sizeof(*StrPtrArr[1]) - is quite strange....
actually sizeof(StrPtrArr[1]) also cannot provide correct value.
You should remember size of allocated memory and then use it like:
size_t arrSize = 10 + 1;
StrPtrArr[1] = (char *)malloc(arrSize);
. . .
strncpy_s(StrPtrArr[1], arrSize, InpBuf1, _TRUNCATE);
The problem is that you are using sizeof when deciding how many characters to copy. However, you allocated a fixed number of characters which is not known to sizeof operator: sizeof StrPtrArr[0] is equal to the size of char pointer on your system (four bytes, judging from the output), not 10 + 1. Hence, you need to specify that same number again in the call to secure string copy.
It isn't as complicated as people seem to think.
char* array = calloc( n, sizeof(array[0]) ); // allocate array of pointers
// assign a dynamically allocated pointer:
size_t size = strlen(str) + 1;
array[i] = malloc(size);
memcpy(array[i], str, size);
I intentionally used calloc during allocation, since that sets all pointers to NULL. This gives the advantage that you can harmlessly call free() on the pointer, even before it is assigned to point at a string.
This in turn means that you can easily (re)assign a new string to an index at any time, in the following way:
void str_assign (char** dst, const char* src)
{
size_t size = strlen(src) + 1;
free(*dst);
*dst = malloc(size);
if(*dst != NULL)
{
memcpy(*dst, src, size);
}
}
...
str_assign(&array[i], "something");
I have this code right here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int *size;
int i = 0;
char buf[] = "Thomas was alone";
size = (int*)calloc(1, sizeof(buf)+1);
for(i=0; i<strlen(buf); i++)
{
*(size+i) = buf[i];
printf("%c", *(size+i));
}
free(size);
}
To my understanding calloc reserves a memspace the size of the first arg multiplied by the second, in this case 18. The length of buf is 17 and thus the for loop should not have any problems at all.
Running this program results in the expected results ( It prints Thomas was alone ), however it crashes immediately too. This persists unless I crank up the size of calloc ( like multiplied by ten ).
Am I perhaps understanding something wrongly?
Should I use a function to prevent this from happening?
int *size means you need:
size = calloc(sizeof(int), sizeof(buf));
You allocated enough space for an array of char, but not an array of int (unless you're on an odd system where sizeof(char) == sizeof(int), which is a theoretical possibility rather than a practical one). That means your code writes well beyond the end of the allocated memory, which is what leads to the crashing. Or you can use char *size in which case the original call to calloc() is OK.
Note that sizeof(buf) includes the terminal null; strlen(buf) does not. That means you overallocate slightly with the +1 term.
You could also perfectly sensibly write size[i] instead of *(size+i).
Change the type of size to char.
You are using an int and when you add to the pointer here *(size+i), you go out of bounds.
Pointer arithmetic takes account of the type, which in you case is int not char. sizeof int is larger than char on your system.
You allocate place for char array not for int array:
char is 1 byte in memory (most often)
int is 4 bytes in memory (most often)
so you allocate 1 * sizeof(buf) + 1 = 18 bytes
so for example in memory:
buf[0] = 0x34523
buf[1] = 0x34524
buf[2] = 0x34525
buf[3] = 0x34526
but when you use *(size + 1) you don't move pointer on 1 byte but for sizeof(int) so for 4 bytes.
So in memory it will look like:
size[0] = 0x4560
size[1] = 0x4564
size[2] = 0x4568
size[3] = 0x4572
so after few loops you are out of memory.
change calloc(1, sizeof(buf) + 1); to calloc(sizeof(int), sizeof(buf) + 1); to have enough memory.
Second think, I think is some example on which you learn how it works?
My suggestion:
Use the same type of pointer and variable.
when you assign diffnerent type of variables, use explicit conversion, in this example
*(size+i) = (int)buf[i];
This piece of code causes segmentation fault:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLIDINGWINDOW 5
#define SEGMENTSIZE 100
int main() {
char** send_buffer = (char**) malloc (SLIDINGWINDOW);
int i;
for (i = 0; i<SLIDINGWINDOW; ++i) {
send_buffer[i] = (char*) malloc (SEGMENTSIZE);
}
for (i = 0; i<SLIDINGWINDOW; ++i) {
strcpy(send_buffer[i], "Hello, world");
printf("%s\n", send_buffer[i]);
fflush(NULL);
}
}
The strange thing is if you put the content of the second loop into the first loop, it works!
Could anyone see why this happens?
Many thanks!
The size passed to malloc() isn't correct. You probably meant:
char** send_buffer = malloc (SLIDINGWINDOW * sizeof(send_buffer[0]));
and
send_buffer[i] = malloc (SEGMENTSIZE * sizeof(send_buffer[i][0]));
This is because the argument to malloc() is the number of bytes you're asking for, so you need to multiply the length you want by the size of the elements.
In addition, you should also check that the value returned from malloc() isn't NULL.
Note that I've removed the cast from the malloc call - in C, the cast isn't required, and can sometimes mask an error.
A further improvement would be to use strncpy() to ensure that you're not going to write characters after the end of the segment:
strncpy(send_buffer[i], "Hello, world", SEGMENTSIZE);
Note that in the case that the source string is larger than SEGMENTSIZE, then the destination string will not be null terminated. You can fix this with a:
send_buffer[i][SEGMENTSIZE - 1] = '\0';
after the strncpy().
This will produce only enough space for SLIDINGWINDOW bytes:
malloc (SLIDINGWINDOW)
You want enough space for SLIDINGWINDOW pointers:
malloc (SLIDINGWINDOW * sizeof(char*))
Your second malloc() is correct by luck; sizeof(char) is always 1.
This question already has answers here:
Facing an error "*** glibc detected *** free(): invalid next size (fast)"
(2 answers)
Closed 8 years ago.
When I compile and run this code, I get an error. The error message is:
realloc(): invalid next size: 0x0000000002119010
The file input has about 4000 words.
I debugged it, but I can not find any problem.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_LEN 10 //buf length
int main(int argc, char *argv[])
{
int file_d; //file descriptor
char *ct_head; //content_first_char
char *content;
ssize_t read_len = BUF_LEN; //had read length
int mem_block_count = 0;
file_d = open("input", O_RDONLY);
if (file_d < 0)
{
perror("open");
exit (1);
}
content = ct_head = (char *) malloc(sizeof(char) * BUF_LEN);
mem_block_count = 1;
while (read_len == BUF_LEN)
{
read_len = read(file_d, ct_head, BUF_LEN);
if (read_len < 0)
{
perror("read");
exit(2);
}
if (read_len == BUF_LEN)
{
ct_head = (char *)realloc(content, sizeof(char) *(++mem_block_count));
ct_head = &content[(mem_block_count-1) * BUF_LEN];
}
else
ct_head[read_len] = '\0';
}
printf("%s", content);
close(file_d);
free(content);
return 0;
}
I'm not sure what your problem is but these lines:
ct_head = (char *)realloc(content, sizeof(char) *(++mem_block_count));
ct_head = &content[(mem_block_count-1) * BUF_LEN];
Are very dodgy. After the first line, ct_head points to the realloced block and content points to garbage. Then the second line reads content and re-assigns ct_head - leaking the realloced memory.
I suspect you may just have memory corruption in your program?
I think
ct_head = (char *)realloc(content, sizeof(char) *(++mem_block_count));
should be:
content = (char *)realloc(content, sizeof(char) *(++mem_block_count) * BUF_LEN);
if (content == NULL)
{
// do something if the realloc fails
}
The first time you use realloc, it allocates only 2 bytes because, going into the call, sizeof(char) is 1 and mem_block_count is also 1 (and it is then pre-incremented to 2).
This means the next read will overrun the buffer it has allocated. I suspect you need to also multiply by BUF_LEN in your realloc.
Edit
I've just realised, it's even worse: straight after allocating content to 2 bytes, you set ct_head to BUF_LEN bytes beyond the start of content. This means your read overwrites an area that is totally outside the buffer.
You've already got some good answers here, but here's a little bit of advice that won't fit in a comment. In C, sizeof(char) is always 1. It is 1 by definition, so it is as redundant as using (1 * BUF_LEN). Also in C, you don't have to [and shouldn't] cast the result of malloc. Doing so can mask a fundamental error1.
If you want to allocate space depending on the size of a type, use:
ct_head = malloc(sizeof(*ct_head) * BUF_LEN);
That way, if the type of ct_head changes, you'll still be allocating enough space, without having to change all the calls to malloc and realloc.
1. If you do not include the appropriate header for malloc, then a C compiler will assume that malloc returns int, and this may cause issues on platforms where the size of an int differs from the size of a pointer type. Also, conversions from integer types to pointer types are implementation-defined.