I have an error using realloc to replace malloc.
This code below runs OK on my computer.
int vector_grow(Vector* vec) {
unsigned long newcap;
int * newarr;
if (0 == vec->cap) {
vec->arr = (int*)malloc(START_CAPACITY * sizeof(*vec->arr));
if (NULL == vec->arr)
return -1;
vec->cap = START_CAPACITY;
return 0;
}
newarr = malloc (newcap * sizeof(*vec->arr));
if (NULL == newarr)
return -1;
memcpy (newarr, vec->arr, vec->len * sizeof(*vec->arr));
free (vec->arr);
vec->arr = newarr;
vec->cap = newcap;
return 0;
}
I want to change the malloc to realloc, but the error occurs.
int vector_grow(Vector* vec) {
unsigned long newcap;
if (0 == vec->cap) {
vec->arr = (int*)malloc(START_CAPACITY * sizeof(*vec->arr));
if (NULL == vec->arr)
return -1;
vec->cap = START_CAPACITY;
return 0;
}
newcap = 2 * vec->cap;
if ((vec->arr = (int*)realloc(vec->arr, newcap * sizeof(int))) == NULL)
return -1;
return 0;
}
It says
malloc: *** error for object 0x7fca64c02598: incorrect checksum for freed object - object was probably modified after being freed.
I don't know any difference between those two snippets of code, if you know what causes the error, please tell me! Thank you very much!
Bug in missing vec->cap = in updated code certainly contribute to various calls to malloc() and calling code's misuse of data.
int vector_grow(Vector* vec) {
unsigned long newcap;
if (0 == vec->cap) {
... // not important to show the bug
}
newcap = 2 * vec->cap;
if ((vec->arr = (int*)realloc(vec->arr, newcap * sizeof(int))) == NULL)
return -1;
// Add missing update
vec->cap = newcap;
return 0;
}
Also better to test for allocation success
void *p = realloc(vec->arr, sizeof *(vec->arr) * newcap);
if (p == NULL) {
return -1;
}
vec->arr = p;
vec->cap = newcap;
The only scenario where I can imagine such error message is when you actually modify the pointer, for example
int *x = malloc(2 * sizeof *x);
if (x != NULL) {
x = x + 1;
free(x);
}
The pointer that MUST be passed to free() MUST had been returned by malloc()/calloc()/realloc(), passing any other pointer including a pointer to the same data but at a different position like x in the example above is undefined behavior.
Related
I am solving binary tree paths leet code programming question 257. I am having issue for one of the larger input where my code is getting segmentation fault. I suspect that there is an problem with my realloc but I am not able to figure it out.
Below is my approach:
Initially I started by dynamically allocating 80 bytes of memory of type char (80/8 = 10 rows)and storing the returned address to char **res variable.
char ** res = (char **)malloc(sizeof(char *) * sum);
I am calling findpath function recursively to find all the binary tree paths. Whenever one path is found , I dynamic allocate 100 bytes for each row index.
res[resIdx] = (char *)malloc(sizeof(char) * 100);
I have one global variable resIdx which points to the current row index where I copy the found binary tree path and increment the global variable resIdx.
if the resIdx becomes greater then total number of rows which was previously allocated then I do realloc of the memory but it looks like realloc is getting failed.
if (resIdx >= sum)
{
sum = sum + 10;
res = (char **)realloc(res,sizeof(char *) * sum); //Any issue here?
}
Can anyone please help me to figure out what's wrong I am doing in my code. Below is my full code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int sum;
int resIdx;
void findpath (struct TreeNode* root, int *ls,int ls_idx,char **res);
char ** binaryTreePaths(struct TreeNode* root, int* returnSize){
if (root == NULL)
{
*returnSize = 0;
return NULL;
}
resIdx = 0;
sum = 10;
char ** res = (char **)malloc(sizeof(char *) * sum);
int ls[100];
findpath(root,&ls[0],0,res);
*returnSize = resIdx;
return &res[0];
}
void findpath (struct TreeNode* root, int *ls,int ls_idx,char **res)
{
char temp[100];
int l=0,i=0;
if (root->left == NULL && root->right == NULL)
{
ls[ls_idx] = root->val;
ls_idx+=1;
if (resIdx >= sum)
{
sum = sum + 10;
res = (char **)realloc(res,sizeof(char *) * sum);
}
res[resIdx] = (char *)malloc(sizeof(char) * 100);
while (i < ls_idx)
{
if (i==0)
{
l = l + sprintf(&temp[l], "%d", ls[i]);
}
else
{
l = l + sprintf(&temp[l], "->%d", ls[i]);
}
i++;
}
strcpy(res[resIdx],temp);
resIdx++;
return;
}
ls[ls_idx] = root->val;
if (root->left != NULL)
{
findpath(root->left,ls,ls_idx+1,res);
}
if (root->right != NULL)
{
findpath(root->right,ls,ls_idx+1,res);
}
return;
}
The last argument to your findPath function is declared as a char** type; thus, when you make the call findpath(root,&ls[0],0,res); in binaryTreePaths, where the res variable is a char** type, a copy of that pointer is passed to the findPath function (most likely, but not necessarily, by placing that copy on the stack).
Then, if reallocation is required, the res = (char **)realloc(res,sizeof(char *) * sum); line in that function overwrites the value in the passed copy and, at the same time (if the call is successful – vide infra), will (probably) invalidate (i.e. free) the memory referenced by the previous address in that res copy. Thus, when control returns to the calling binaryTreePaths function, its own version of res will not have been modified and will remain pointing to that (now invalid) memory.
So, in order for your findPath function to be able to modify the given res argument, that must be passed as a pointer – in this case, a pointer to a char**, which will be of type char***; then, when called, you will need to pass the address of the res variable in binaryTreePaths.
Note also that directly overwriting a pointer in a call to realloc, as you have done in the line of code quoted above is dangerous. This is because, should that call fail, then you have lost the original data pointer (it will have been overwritten with NULL) and error recovery will be very difficult. You should save the return value in a temporary variable and only replace your original if the call succeeds.
With the code you have provided, I cannot properly test for any other errors but, taking the points above in hand, the below is a possible fix. See also: Do I cast the result of malloc?
int sum;
int resIdx;
void findpath(struct TreeNode* root, int* ls, int ls_idx, char*** res); // Note last argument type!
char** binaryTreePaths(struct TreeNode* root, int* returnSize)
{
if (root == NULL) {
*returnSize = 0;
return NULL;
}
resIdx = 0;
sum = 10;
char** res = malloc(sizeof(char*) * sum);
int ls[100];
findpath(root, &ls[0], 0, &res); // Pass ADDRESS of res
*returnSize = resIdx;
return &res[0];
}
void findpath(struct TreeNode* root, int* ls, int ls_idx, char*** res)
{
char temp[100];
int l = 0, i = 0;
if (root->left == NULL && root->right == NULL) {
ls[ls_idx] = root->val;
ls_idx += 1;
if (resIdx >= sum) {
sum = sum + 10;
char** test = realloc(*res, sizeof(char*) * sum);
if (test == NULL) {
// Handle/signal error
return;
}
*res = test; // Only replace original if realloc succeeded!
}
(*res)[resIdx] = malloc(sizeof(char) * 100);
while (i < ls_idx) {
if (i == 0) {
l = l + sprintf(&temp[l], "%d", ls[i]);
}
else {
l = l + sprintf(&temp[l], "->%d", ls[i]);
}
i++;
}
strcpy((*res)[resIdx], temp);
resIdx++;
return;
}
ls[ls_idx] = root->val;
if (root->left != NULL) {
findpath(root->left, ls, ls_idx + 1, res);
}
if (root->right != NULL) {
findpath(root->right, ls, ls_idx + 1, res);
}
return;
}
Note: I did call this function and free it main but valgrind still shows error.
This code basically takes in a singly linked-list with two data coeff and exp. This is basically converting a polynomial store in a linked list converted to readable string. I looking to have it dynamic allocated.
char *Poly_to_string(const Polynomial *p)
{
char *x = malloc(1);
int size;
while (p != NULL)
{
if((p->exp != 0) && (p->exp != 1))
{
size = asprintf(&x, "%s%dx^%d + ", x, p->coeff, p->exp);
if (size == -1)
{
exit(-1);
}
}
else if(p->exp == 1)
{
size = asprintf(&x, "%s%dx + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
else if(!p->exp)
{
size = asprintf(&x, "%s%d + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
p = p->next;
}
x[strlen(x) - 3] = '\0';
return x;
}
From the Linux asprintf() man page (bolding mine):
DESCRIPTION
The functions asprintf() and vasprintf() are analogs of
sprintf(3) and vsprintf(3), except that they allocate a string
large enough to hold the output including the terminating null
byte ('\0'), and return a pointer to it via the first argument.
This pointer should be passed to free(3) to release the allocated
storage when it is no longer needed.
RETURN VALUE
When successful, these functions return the number of bytes
printed, just like sprintf(3). If memory allocation wasn't
possible, or some other error occurs, these functions will return
-1, and the contents of strp are undefined.
This line is wrong:
char *x = malloc(1);
It should just be
char *x;
because if asprintf() works, it will overwrite the contents of x and cause the memory allocated in char *x = malloc(1); to be leaked.
EDIT
The looping also needs to be addressed, as you're trying to grow the string:
char *Poly_to_string(const Polynomial *p)
{
// start with an empty string that can be free()'d
// (if you don't have strdup() use malloc() and strcpy())
char *x = strdup("");
int size;
while (p != NULL)
{
// save the old malloc()'d value so it can be free()'d
char *oldValue = x;
if((p->exp != 0) && (p->exp != 1))
{
size = asprintf(&x, "%s%dx^%d + ", x, p->coeff, p->exp);
if (size == -1)
{
exit(-1);
}
}
else if(p->exp == 1)
{
size = asprintf(&x, "%s%dx + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
else if(!p->exp)
{
size = asprintf(&x, "%s%d + ", x, p->coeff);
if (size == -1)
{
exit(-1);
}
}
// free() the old value
free(oldValue);
p = p->next;
}
x[strlen(x) - 3] = '\0';
return x;
}
There are other ways to do this without the initial char *x = strdup(""); but the code then becomes a lot more complex.
You're not deallocating variable x
void put(char* key, int value)
{
int i = 0;
// Iterate through elements of hashtable
while (array[i].flag == 1)
{
// If key already exists, update the value
// and return
if (strcmp(array[i].data->key, key) == 0)
{
array[i].data->value = value;
return;
}
i = i + 1;
// Error Handling, when end of hashtable is reached
if (i == max)
{
i = 0;
// p rintf("\n Hash table is full, cannot insert any more item \n");
// return;
}
}
// Insert new item into the hashtable
array[i].flag = 1;
array[i].data = (struct item*) malloc(sizeof(struct item));
array[i].data->key = (char *)malloc((strlen(key)+1)*sizeof(char));
// so here I have to use snprintf instead of strcy because it's
// forbidden, and I don't know how
**strcpy(array[i].data->key, key);**
//snprintf(array[i].data->key,sizeof(key),"%s",key);
array[i].data->value = value;
}
Firstly, never cast malloc, and do not forget verify the return value of malloc.
array[i].data = malloc(sizeof(struct item));
if (!array[i].data) {
// handle error
return; // for example
}
array[i].data->key = malloc((strlen(key)+1)*sizeof(char));
if (!array[i].data->key) {
// handle error
}
Using strlen instead of sizeof that returns the size of pointer, not the length of string:
snprintf(array[i].data->key, strlen(key) + 1,"%s", key);
here I have to use snprintf instead of strcy because it's forbidden, and I don't know how
strcpy() can overflow is the destination is insufficient. That really does not apply here as the needed space is allocated.
// array[i].data = (struct item*) malloc(sizeof(struct item));
// array[i].data->key = (char *)malloc((strlen(key)+1)*sizeof(char));
// strcpy(array[i].data->key, key);
array[i].data = malloc(sizeof *(array[i].data));
size_t sz = strlen(key) + 1;
array[i].data->key = malloc(sz);
snprintf(array[i].data->key, sz, "%s", key);
// or
strcpy(array[i].data->key, key);
// or
memcpy(array[i].data->key, key, sz);
Cast not needed
size of of referenced data better to use that sizeof type.
Avoid 2 trips finding the length.
Returns check omitted for brevity.
With checks
array[i].data = malloc(sizeof *(array[i].data));
if (array[i].data == NULL) return fail; // or do something to indicate error
size_t sz = strlen(key) + 1;
array[i].data->key = malloc(sz);
if (array[i].data->key == NULL) return fail;
int count = snprintf(array[i].data->key, sz, "%s", key);
if (count < 0 || (unsigned) count >= sz) return fail;
Primary mistake
OP's attempt fails as sizeof(key) is the size of a pointer, perhaps 2, 4 or 8. Instead, what is needed is the size of the allocation for array[i].data->key as in sz (see above) or strlen(key) + 1.
snprintf(array[i].data->key,sizeof(key),"%s",key); // bad
Consider this program:
int main(void)
{
int* i = malloc(sizeof(int));
int* j = malloc(sizeof(int));
}
However this is a naive approach, because malloc may fail and the pointers are not free'd.
So you can do this:
int main(void)
{
int* i;
int* j;
if ((i = malloc(sizeof(int)) < 0)
{
return -1;
}
if ((j = malloc(sizeof(int)) < 0)
{
free(i);
return -1;
}
free(i);
free(j);
}
However I consider this very error-prone. Consider having to assign 20 pointers, in the last malloc error case, you have to free 19 variables and then return -1.
I also know atexit, which can help me to write it like this:
int* i;
int* j;
void del_i(void)
{
free(i);
}
void del_j(void)
{
free(j);
}
int main(void)
{
if ((i = malloc(sizeof(int)) < 0)
{
return -1;
}
else
{
atexit(del_i);
}
if ((j = malloc(sizeof(int)) < 0)
{
return -1;
}
else
{
atexit(del_j);
}
}
Which is better, but I dislike having to declare all pointers as global. Is there some way to combine these two approaches, basically:
Having destructors for pointers, which can be either executed directly or be used with atexit.
Having pointers local to functions.
free on NULL is defined to be a safe no-op. So a non-jumping variation could be:
int *i = malloc(sizeof(int));
int *j = malloc(sizeof(int));
if(i && j)
{
// do some work
}
free(i);
free(j);
First, this will not detect malloc failure:
if ((i = malloc(sizeof(int)) < 0)
{
return -1;
}
malloc returns NULL on failure, not a negative number.
Second, atexit is good for cleaning up static and global objects. It is not a good idea to make local objects global only to use them inside atexit.
A better approach is to make a struct for all related pointers that you need to allocate in an all-or-nothing unit, define a function for freeing them all at once, and write a function that allocates them one by one with memory checking on each allocation:
typedef struct AllOrNothing {
double *dPtr;
int *iPtr;
float *fPtr;
size_t n;
} AllOrNothing;
void freeAllOrNothing(AllOrNothing *ptr) {
free(ptr->dPtr);
free(ptr->iPtr);
free(ptr->fPtr);
free(ptr);
}
int allocateAllOrNothing(size_t n, AllOrNothing **res) {
*res = malloc(sizeof(AllOrNothing));
if (*res == NULL) {
return -1;
}
// Freeing NULL is allowed by the standard.
// Set all pointers to NULL upfront, so we can free them
// regardless of the stage at which the allocation fails
(*res)->dPtr = NULL;
(*res)->iPtr = NULL;
(*res)->fPtr = NULL;
(*res)->n = n;
(*res)->dPtr = malloc(n*sizeof(double));
if ((*res)->dPtr == NULL) {
free(*res);
*res = NULL;
return -1;
}
(*res)->fPtr = malloc(n*sizeof(float));
if ((*res)->fPtr == NULL) {
free(*res);
*res = NULL;
return -1;
}
(*res)->iPtr = malloc(n*sizeof(int));
if ((*res)->iPtr == NULL) {
free(*res);
*res = NULL;
return -1;
}
return 0;
}
int main(void)
{
int* i = NULL; // Init with NULL otherwise free on none NULL possible
int* j = NULLL;
if (!(i = malloc(sizeof(int)))
{
goto exit;
}
if (!(j = malloc(sizeof(int)))
{
goto exit;
}
...
exit:
free(i);
free(j);
...
return err;
}
This is something you can solve with goto statements.
int main(void)
{
int* i = NULL;
int* j = NULL;
bool success = false;
do {
i = malloc(sizeof(int));
if (NULL == i) break;
j = malloc(sizeof(int));
if (NULL == j) break;
success = true;
} while (0);
if (!success)
{
printf("Something failed!");
}
else
{
printf("All succeeded!");
// Do more work
}
free(i);
free(j);
return (success? 0 : 1);
}
Avoid multiple exit points. Avoid interlacing allocation and error handling. Follows a clean order of operation:
Declare, allocate and initialize resources..
If all successful, do the task.
Clean-up.
Return status.
// Do all allocations first, test their `NULL`-ness, then free them all.
int main(void) {
// Allocate resources
// declare and allocate in one step
int* i = malloc(sizeof *i);
double* j = malloc(sizeof *j);
// Test for acceptability
bool ok = i && j;
// Perform the main body of code
if (ok) {
; // do normal process in the code;
}
// free resources
free(i);
free(j);
// return status
return ok ? 0 : -1;
}
int *i=NULL,*j=NULL;
if(!(i=malloc(sizeof(int))))
goto EXIT;
if(!(j=malloc(sizeof(int))))
goto EXIT;
/* do some work */
return 0;
EXIT:
free(i);
free(j);
exit(EXIT_FAILURE);
Although goto is considered a bad programming practice
but here we can use it to get our task done with ease and simplicity
In implementation of list (Python 3.4) I saw the following:
static int
list_resize(PyListObject *self, Py_ssize_t newsize)
{
PyObject **items;
size_t new_allocated;
Py_ssize_t allocated = self->allocated;
/* Bypass realloc() when a previous overallocation is large enough
to accommodate the newsize. If the newsize falls lower than half
the allocated size, then proceed with the realloc() to shrink the list.
*/
if (allocated >= newsize && newsize >= (allocated >> 1)) {
assert(self->ob_item != NULL || newsize == 0);
Py_SIZE(self) = newsize;
return 0;
}
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
/* check for integer overflow */
if (new_allocated > PY_SIZE_MAX - newsize) {
PyErr_NoMemory();
return -1;
} else {
new_allocated += newsize;
}
if (newsize == 0)
new_allocated = 0;
items = self->ob_item;
if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *)))
PyMem_RESIZE(items, PyObject *, new_allocated);
else
items = NULL;
if (items == NULL) {
PyErr_NoMemory();
return -1;
}
self->ob_item = items;
Py_SIZE(self) = newsize;
self->allocated = new_allocated;
return 0;
}
and concretely line:
PyMem_RESIZE(items, PyObject *, new_allocated);
How I know, realloc may return another pointer, different from the obtained. I don`t understand how it works stable.
This is the definition of PyMem_Resize:
#define PyMem_Resize(p, type, n) \
( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
So it modifies the pointer items in-place.
See also https://docs.python.org/3/c-api/memory.html#c.PyMem_Resize