Problems with 'Heap Buffer' Error in C - c

I get the following error in my C program:
Writing to heap after end of help buffer
Can you tell me what I'm missing?
char * path_delimiter(char * path)
{
int i = 0, index = 0, size = 0, length = (int)strlen(path);
char *tmp, *ans;
for(; i < length; i++) {
if(path[i] == PATH_DELIM[0]) {
break;
}
}
i++;
size = (int)strlen(path) - i;
ans = (char*)malloc(sizeof(path));
tmp = (char*)malloc(size);
strcpy(ans,path);
ans[i-1] = END_ARRAY;
if(size > 0)
{
strcpy(tmp,&path[i]);
realloc(path,size);
strcpy(path,tmp);
}
else
{
strcpy(path,ans);
}
free(tmp);
return ans;
}

This ...
sizeof(path)
... is the same as ...
sizeof(char *)
... which is the size of the pointer (not the size of the buffer which it's pointing to), so it's probably about 4.
So this ...
ans= (char*)malloc(sizeof(path));
... is a 4-byte buffer, and so this ...
strcpy(ans,path);
... is overwriting (writing past the end of) that buffer.
Instead of ...
malloc(sizeof(path));
... I think you want ...
malloc(strlen(path)+1);

You are not checking if malloc and realloc succeeded. More importantly, realloc may return a different handle which you are discarding.
Further, you have:
ans = malloc(sizeof(path));
...
strcpy(ans, path);
On the most common platform today, sizeof(path) is most likely 4 or maybe 8, regardless of the length of the character array path points to.

You normally need size = strlen(xxx) + 1; to allow for the null terminator on the string.
In this case, I think you need:
size = strlen(path) - i + 1;

Related

My own substring function | valgrind showing some malloc errors I do not understand

Task:
Allocate (with malloc(3)) and return a substring from the string s. The substring begins at index start and is of maximum size len.
Return value: The substring. NULL if the allocation fails.
Hello, after a few hours I decided to ask for some clarifications. I have the following functions and some error from Valgrind I can't understand, that shows up even if everything is correct. (ft_strlen(s) I call from my own library, where also lib for malloc is put).
char *ft_substr(char const *s, unsigned int start, size_t len)
{
unsigned int x;
char *a;
unsigned int i;
i = 0;
if (s == NULL)
return (0);
if (start > ft_strlen(s))
{
if (!(a = (char *)malloc(0*sizeof(char))))
return (0);
return (a);
}
if ((start + len) < ft_strlen(s))
x = len;
else
x = ft_strlen(s) - start;
if (!(a = (char *)malloc((x + 1) * sizeof(char))))
return(0);
while (i < x)
{
a[i] = s[start + i];
i++;
}
a[i] = '\0';
return (a);
}
I left there one error on purpose. If I am suppose to return null if allocation fails, why below instead of 0 should be 1? Anyway it does not change the errors presented below.
if (!(a = (char *)malloc(0 * sizeof(char))))
ERRORS:
==4817== Invalid read of size 1
==4817== at 0x483FED4: strcmp (in /usr/lib/x86_64-linux-gnu/valgrind vgpreload_memcheck-amd64-linux.so)
==4817== by 0x4039BC: main (ft_substr_test.cpp:28)
==4817== Address 0x4dad0d0 is 0 bytes after a block of size 0 alloc'd
==4817== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4817== by 0x403B58: ft_substr (in /home/tony/42cursus/0lvl_libft_1week/libftTester/a.out)
==4817== by 0x4039A4: main (ft_substr_test.cpp:27)
==4817==
Your function has multiple problems:
the type of start, x and i should be size_t.
malloc(0) has implementation defined behavior. You should allocate at least 1 byte for the null terminator and set it before returning the pointer to the empty string or return NULL if the specification says you should.
the function should call ft_strlen() just once.
the special case for start > ft_strlen(s) can be handled in the general case if an empty string should be returned.
Here is a modified version:
char *ft_substr(char const *s, size_t start, size_t len) {
size_t i, slen;
char *a;
if (s == NULL) {
return NULL;
}
slen = ft_strlen(s);
if (start > slen) {
start = slen;
}
if (len > slen - start) {
len = slen - start;
}
if (!(a = malloc((len + 1) * sizeof(char)))) {
return NULL;
}
for (i = 0; i < len; i++) {
a[i] = s[start + i];
}
a[i] = '\0';
return a;
}
PS: you may need to reformat the code to fit the local 42 norminette...
On Linux systems, calling malloc(0) will not necessarily return a NULL pointer. It could return a pointer that your can't write to but can pass to free.
So when you return the result of malloc(0) from the function the calling function sees a non-null pointer and attempts to dereference it. Since this pointer essentially points to a buffer of size 0, attempting to read it reads past the end of the buffer, which is what valgrind is complaining about.
You can fix this by either returning NULL:
if (start > ft_strlen(s))
{
return NULL;
}
Or by allocating space for an empty string and setting the null byte:
if (start > ft_strlen(s))
{
if (!(a = malloc(1)))
return NULL;
*a = 0;
return a;
}
A few other notes:
sizeof(char) is defined to be 1, so you can leave it out of size calculations
Don't cast the return value of malloc.
Use NULL instead of 0 for null pointers
Parenthesis aren't required around the expression in a return statement.

Returning a char** gives me error "Address 0x0 is not stack'd, malloc'd or free'd

I need to return a list of strings. Those strings are read from the file (each string in each line of the file). The code below is not working:
void getStrings(char **container, FILE* file, int *numberOfLetters) {
char* line = NULL;
size_t l = 0;
ssize_t r;
container = (char**) malloc (sizeof(char*));
size_t lettersNumber= 1;
size_t numberOfStrings = 0;
size_t sizeOfContainer = 1;
while ((r = getline(&line, &l, file)) != -1) {
line[strlen(line) - 1] = '\0';
lettersNumber = lettersNumber + strlen(line);
if (numberOfStirngs == sizeOfContainer) {
sizeOfContainer= sizeOfContainer * 2;
char** temp = calloc(sizeOfContainer, sizeof(char**));
for (int k = 0; k < l; k++) {
temp[k] = container[k];
}
free(container);
container = temp;
}
container[numberOfStrings] = line;
numberOfStrings++;
}
if (line) {
free(line);
}
Because you calloc the whole array of pointers in each step, you loose all the strings from previous iterations and always only keep the last line. Since you use calloc, all these pointers are null, thus your error message.
The tool that is foreseen for such things is realloc and not malloc or calloc to keep the values that you already have stored.
There seem to be other things wrong, too. E.g you have only one line, all your lines are copied into that one, so previous lines are always overwritten. As BLUEPIXY correctly notes, you only change the value of your function parameter to the new values, you never return the new value to the caller.
Then, re-allocating memory in each iteration is a real waste. You should think of a strategy to do that more efficiently.

Invalid read when running under valgrind

gcc (GCC) 4.7.2
valgrind-3.8.1
c89
Hello,
==1160== Invalid read of size 1
==1160== at 0x8048C94: get_input_values (parse_cmd_input.c:278)
==1160== by 0x8048BA0: parse_input (parse_cmd_input.c:245)
==1160== by 0x80489A1: main (parse_cmd_input.c:50)
==1160== Address 0x40ef02c is 0 bytes after a block of size 4 alloc'd
==1160== at 0x40072C5: calloc (vg_replace_malloc.c:593)
==1160== by 0x8048B28: parse_input (parse_cmd_input.c:239)
==1160== by 0x80489A1: main (parse_cmd_input.c:50)
So its saying the address is reading a zero bytes of a allocated size of 4, and is trying to read 1 byte from it. However, I haven't over stepped the bounds of the array and I am accessing element 0.
I have checked with gdb, and element zero contains a character.
My program doesn't crash, and seems to work fine. But it might cause a problem on a production server.
I am not sure if I am correct here:
Should this be:
cpy_input = calloc(strlen(input) + 1, sizeof(char*));
or:
cpy_input = calloc(strlen(input) + 1, sizeof(char));
A char is 1 byte, and a pointer to a char is 4 bytes on my system.
The string passed in would be something like this "25 b"
int parse_input(const char *input)
{
char *cpy_input = NULL;
int has_error = -1;
if(strlen(input) == 0) {
LOG_ERR("FAILED: Empty string");
return -1;
}
cpy_input = calloc(strlen(input) + 1, sizeof(char));
apr_cpystrn(cpy_input, input, sizeof(cpy_input));
LOG_INFO("[ %s ]", cpy_input);
memset(&channel, 0, sizeof channel);
has_error = get_input_values(cpy_input, &channel);
free(cpy_input);
return has_error;
}
int get_input_values(const char *str, channel_t *channel)
{
size_t i = 0;
size_t k = 0;
int upper_flag = 0;
/* Indicates no digits or command found*/
channel->lower = -1;
channel->upper = -1;
channel->cmd = -1;
#define DIG_BUFFER_SIZE 32
char dig_buffer_lower[DIG_BUFFER_SIZE];
char dig_buffer_upper[DIG_BUFFER_SIZE];
if(strlen(str) == 0) {
LOG_ERR("FAILED: Empty string");
return -1;
}
memset(dig_buffer_lower, 0, DIG_BUFFER_SIZE);
memset(dig_buffer_upper, 0, DIG_BUFFER_SIZE);
LOG_INFO("SIZE %d %d", sizeof(char), sizeof(char*));
/* Increament and check for digits */
for(i = 0; i < DIG_BUFFER_SIZE; i++) {
switch(str[i]) {
case 32: /* ignore space */
continue;
case 45: /* '-' Start upper bounds */
LOG_DEBUG("Found a '-' check upper value");
/* Having a second '-' means the string is invalid */
if(!upper_flag) {
upper_flag = 1;
k = 0;
}
break;
} /* switch */
/* Insert on digits into the lower and upper values */
if(isdigit(str[i])) {
if(upper_flag) {
dig_buffer_upper[k++] = str[i];
LOG_DEBUG("dig_buffer_upper[%d] %s", i, dig_buffer_upper);
}
else {
/* Add to digit buffer */
dig_buffer_lower[k++] = str[i];
LOG_DEBUG("dig_buffer_lower[%d] %s", i, dig_buffer_lower);
}
}
} /* for loop */
Many thanks for any suggestions,
sizeof(cpy_input) is just sizeof(char *), and not the string length. Instead, say:
apr_cpystrn(cpy_input, input, strlen(input) + 1);
Or better, use a naked strcpy or equivalent. Also there's no need to zero out the array with calloc, since you're just about to overwrite it anyway. And since sizeof(char) is 1 by definition, you can allocate the array with:
cpy_input = malloc(strlen(input) + 1);
(Think about strings for a minute: You're already at the mercy of having a null terminator at a sensible place, or strlen will either crash or return a huge value. Once you trust the result of strlen, you are guaranteed to allocate enough memory to strcpy the string and the null terminator. Alternatively, you can use memcpy for a possibly even more efficient copy, since you know the size.)
Ok, maybe I'm missing something, but your for loop will iterate over 0 .. DIG_BUFFER_SIZE-1, reading from str[i]. I don't see what would cause that loop to break out early, especially since it seems to immediately wrap a switch, and so any break inside the switch would exit the switch, but not the for.
Your calloc(strlen(input) + 1, sizeof(char)); correctly allocates storage for the exact length of input. The code downstream in get_input_values doesn't seem to stop if the string is shorter than DIG_BUFFER_SIZE.
(I'd love to be proven wrong, but to know, we need to see more code.)

Storing text in a char matrix in C

I want to take a text from the standard input and store it into an array of strings. But I want the array of strings to be dynamic in memory. My code right now is the following:
char** readStandard()
{
int size = 0;
char** textMatrix = (char**)malloc(size);
int index = 0;
char* currentString = (char*)malloc(10); //10 is the maximum char per string
while(fgets(currentString, 10, stdin) > 0)
{
size += 10;
textMatrix = (char**)realloc(textMatrix, size);
textMatrix[index] = currentString;
index++;
}
return textMatrix;
}
The result I have while printing is the last string read in all positions of the array.
Example
Reading:
hello
nice
to
meet
you
Printing:
you
you
you
you
you
Why? I've searched over the Internet. But I didn't find this kind of error.
You are storing the same address (currentString) over and over. Try something like
while(fgets(currentString, 10, stdin) > 0)
{
textMatrix[index] = strdup(currentString); /* Make copy, assign that. */
}
The function strdup is not standard (just widely available). It should be easy to implement it yourself with malloc + memcpy.
currentString always point to the same memory area and all the pointers in textMatrix will point to it
char** readStandard()
{
int size = 0;
char** textMatrix = (char**)malloc(size);
int index = 0;
char currentString[10];
while(fgets(currentString, 10, stdin) > 0)
{
size += sizeof(char*);
textMatrix = (char**)realloc(textMatrix, size);
textMatrix[index] = strdup(currentString);
index++;
}
return textMatrix;
}

C string append

I'm looking for an efficient method for appending multiple strings.
The way it should work is C++ std::string::append or JAVA StringBuffer.append.
I wrote a function which actually reallocs previous source pointer and does strcat.
I believe this is not an efficient method as compiler may implement this free and malloc.
Other way I could think of (like std::vector) is allocate memory in bulk (1KB for eg) and do strcpy. In that case every append call will check if the total required allocation is more than (1200 bytes) the amount allocated in bulk, realloc to 2KB. But in that case there will be some memory wasted.
I'm looking for a balance between the above but the preference is performance.
What other approaches are possible. Please suggest.
I would add each string to a list, and add the length of each new string to a running total. Then, when you're done, allocate space for that total, walk the list and strcpy each string to the newly allocated space.
The classical approach is to double the buffer every time it is too small.
Start out with a "reasonable" buffer, so you don't need to do realloc()s for sizes 1, 2, 4, 8, 16 which are going to be hit by a large number of your strings.
Starting out at 1024 bytes means you will have one realloc() if you hit 2048, a second if you hit 4096, and so on. If rampant memory consumption scares you, cap the growth rate once it hits something suitably big, like 65536 bytes or whatever, it depends on your data and memory tolerance.
Also make sure you buffer the current length, so you can do strcpy() without having to walk the string to find the length, first.
Sample function to concatenate strings
void
addToBuffer(char **content, char *buf) {
int textlen, oldtextlen;
textlen = strlen(buf);
if (*content == NULL)
oldtextlen = 0;
else
oldtextlen = strlen(*content);
*content = (char *) realloc( (void *) *content, (sizeof(char)) * (oldtextlen+textlen+1));
if ( oldtextlen != 0 ) {
strncpy(*content + oldtextlen, buf, textlen + 1);
} else {
strncpy(*content, buf, textlen + 1);
}
}
int main(void) {
char *content = NULL;
addToBuffer(&content, "test");
addToBuffer(&content, "test1");
}
I would do something like this:
typedef struct Stringbuffer {
int capacity; /* Maximum capacity. */
int length; /* Current length (excluding null terminator). */
char* characters; /* Pointer to characters. */
} Stringbuffer;
BOOL StringBuffer_init(Stringbuffer* buffer) {
buffer->capacity = 0;
buffer->length = 0;
buffer->characters = NULL;
}
void StringBuffer_del(Stringbuffer* buffer) {
if (!buffer)
return;
free(buffer->characters);
buffer->capacity = 0;
buffer->length = 0;
buffer->characters = NULL;
}
BOOL StringBuffer_add(Stringbuffer* buffer, char* string) {
int len;
int new_length;
if (!buffer)
return FALSE;
len = string ? strlen(string) : 0;
if (len == 0)
return TRUE;
new_length = buffer->length + len;
if (new_length >= new_capacity) {
int new_capacity;
new_capacity = buffer->capacity;
if (new_capacity == 0)
new_capacity = 16;
while (new_length >= new_capacity)
new_capacity *= 2;
new_characters = (char*)realloc(buffer->characters, new_capacity);
if (!new_characters)
return FALSE;
buffer->capacity = new_capacity;
buffer->characters = new_characters;
}
memmove(buffer->characters + buffer->length, string, len);
buffer->length = new_length;
buffer->characters[buffer->length] = '\0';
return TRUE;
}

Resources