I'm having an issue with memory inn valgrind. I've been trying to figure out what's wrong but I can't seem to find it. Here is my issue:
==32233== Invalid write of size 1
==32233== at 0x4C2E1E0: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32233== by 0x4010C7: songCopy (song.c:102)
==32233== by 0x4009E6: main (songtest.c:82)
==32233== Address 0x51fda09 is 0 bytes after a block of size 9 alloc'd
==32233== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32233== by 0x4010A4: songCopy (song.c:101)
==32233== by 0x4009E6: main (songtest.c:82)
And this is where the issue is.
song *songCopy(const song *s)
{
//song *d = NULL ;
mtime *tmp = NULL ;
song *d = malloc(sizeof(song));
d->artist = malloc(sizeof(s->artist) + 1) ;
strcpy(d->artist, s->artist) ;
d->title = malloc(sizeof(s->title) + 1) ;
strcpy(d->title, s->title) ;
if (NULL != s->lastPlayed)
{
// copy the last played
tmp = mtimeCopy(s->lastPlayed) ;
d->lastPlayed = tmp ;
}
else
{
// set lastPlayed to NULL
d->lastPlayed = NULL ;
}
return d ;
}
I've tried dereferencing and adding more space to malloc. I know it's going wrong in the strcpy but I'm not sure why.
You did not show the declaration of song, but from the usage it looks like its artist and title members are char* pointers. You can use sizeof to measure an array, but not a block pointed to by the pointer. sizeof is the same for all char* pointers on your machine, no matter how long is the string to which they point.
You need to use strlen(str)+1 instead of sizeof(str)+1 to fix this problem:
d->artist = malloc(strlen(s->artist) + 1) ;
strcpy(d->artist, s->artist) ;
d->title = malloc(strlen(s->title) + 1) ;
strcpy(d->title, s->title) ;
Related
I am having hard time solving problem with my program. It seems to be running as it should. But when I compile it with adress sanitizer I get heap buffer overflow. The function gets a 2d array containg a word to look for - replace [a][0] and a word next to it, which will be later used to replace it.
const char * findInArray(const char * (*replace)[2], char * start) // function goes through a array 'start' and searches if the word is also in 'replace'
{
char * copy = (char *) malloc (strlen(start)+1); // I made a copy of a field, so I do not modify the one I passed to function
char * total = (char *) malloc (strlen(start)+2); // Here I will add words from copy one by one
memmove(copy,start,strlen(start)+1); // I fill the copy array
char * tokens = strtok (copy," "); // I split copy array
while (tokens != NULL)
{
printf("%lu ",strlen(total));
memmove(total+strlen(total)+1,tokens,strlen(tokens)); // I add words to a new array one by one
memmove (total + strlen(total)," ",1); // at the end of each word I add space
for (int i = 0 ; replace[i][0] != NULL; i++) // I search if word is in array or not, if yes I return its adress
{const char *ptr = strstr(total,replace[i][0]);
if (ptr != NULL) // If there is match - I return pointer to a word that will be replaced
{
free (total);
return replace[i][0];
}
}
//printf("%s\n",tokens);
tokens = strtok(NULL, " ");
}
free (total);
return NULL;
}
The problem if I understand it correctly is that I read values to total array, when It already has been allocated - which does not make a lot of sense to me.
Here is the error message:
==58229==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x000104d00bbb at pc 0x000102c7468c bp 0x00016d562b20 sp 0x00016d5622d8
READ of size 44 at 0x000104d00bbb thread T0
#0 0x102c74688 in wrap_strlen+0x164 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x14688)
#1 0x10289e4dc in findInArray test 4.c:39 // the line of moving memory to total
#2 0x10289ee14 in newSpeak test 4.c:129
#3 0x10289f880 in main test 4.c:186
#4 0x1b4df7e4c (<unknown module>)
0x000104d00bbb is located 0 bytes to the right of 43-byte region [0x000104d00b90,0x000104d00bbb)
allocated by thread T0 here:
#0 0x102c9eca8 in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3eca8)
#1 0x10289e480 in findInArray test 4.c:31 // the line of allocating total array
#2 0x10289ee14 in newSpeak test 4.c:129
#3 0x10289f880 in main test 4.c:186
#4 0x1b4df7e4c (<unknown module>)
Thank you for any help.
Even though the program terminates correctly and gives me the right output, and there are no memory leaks, valgrind gives me some errors of this kind:
Invalid read of size 1
==910== at 0x108DD4: fnv_hash_function (user.c:24)
==910== by 0x108E17: hash (user.c:29)
==910== by 0x109A50: icl_hash_find (icl_hash.c:114)
==910== by 0x1094DB: db_request (user.c:197)
==910== by 0x108D2E: main (tuser.c:65)
==910== Address 0x5416f50 is 0 bytes inside a block of size 15 free'd
==910== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==910== by 0x109152: freeKey (user.c:138)
==910== by 0x109CF2: icl_hash_delete (icl_hash.c:192)
==910== by 0x109796: db_request (user.c:222)
==910== by 0x108CF8: main (tuser.c:59)
==910== Block was alloc'd at
==910== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==910== by 0x108BDC: main (tuser.c:35)
The hash and fnv_hash_function are defined in this way
static inline unsigned int fnv_hash_function( void *key, int len ) {
unsigned char *p = (unsigned char*)key;
unsigned int h = 2166136261u;
int i;
for ( i = 0; i < len; i++ )
h = ( h * 16777619 ) ^ p[i]; //this is the line 24
return h;
}
unsigned int hash(void *key){
return fnv_hash_function(key, strlen(key));
}
I guess the problem is the ^ operator, but I can't figure out what the problem is, since the program terminates with the right output and without segmentation faults.
The icl_hash_find is not a function written by me, but is inside a library I'm using and is defined in this way
void *
icl_hash_find(icl_hash_t *ht, void* key)
{
icl_entry_t* curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key))
return(curr->data);
return NULL;
}
I tried valgrind on the test suite of that library and no errors were found so I doubt the problem is there.
EDIT:
The key is allocated in this for loop:
char * s; //string used as key
for(int i = 0; i < N; i++){
s = (char *)malloc(NAMELEN * sizeof(char));
sprintf(s, "Utente %d", i);
u = create_user( s , i);
if(!db_request(db, s, u, PUT)){
perror("problema PUT");
exit(EXIT_FAILURE);
}
.
.
.
EDIT 2: Here's the body of db_request:
bool db_request(userbase_t *db, char * key, user_t * u, dbop_t op ){
if(db==NULL || key == NULL ||(op!=DELETE && u==NULL)){
errno = EINVAL;
return false;
}
int lock_index; //indice del lock del bucket
switch(op){
//implementazione PUT
case PUT :
lock_index = db -> table -> hash_function(key) % db->nlocks;
WLOCK(&db->locks[lock_index])
errno = 0;
if(icl_hash_insert(db->table, key, (void *) u)==NULL){
RWUNLOCK(&db->locks[lock_index])
//la chiave e' gia' associata ad un utente
if(errno == EINVAL){
perror("key gia' presente");
}
return false;
}
RWUNLOCK(&db->locks[lock_index])
return true;
//implementazione GET
case GET :
lock_index = db -> table -> hash_function(key) % db->nlocks;
RLOCK(&db->locks[lock_index])
u = icl_hash_find(db->table, (void *)key );
RWUNLOCK(&db->locks[lock_index]);
return true;
//implementazione update
case UPDATE :
//elimina il vecchio e aggiunge il nuovo
lock_index = db -> table -> hash_function(key) % db->nlocks;
WLOCK(&db->locks[lock_index]);
if(icl_hash_delete(db->table, key, freeKey, freeUser)){
perror("problema UPDATE (icl_hash_delete) ");
RWUNLOCK(&db->locks[lock_index]);
return false;
}
if (icl_hash_insert(db->table, key, (void *) u)==NULL){
perror("problema UPDATE (icl_hash_insert)");
RWUNLOCK(&db->locks[lock_index]);
return false;
}
case DELETE :
lock_index = db -> table -> hash_function(key) % db->nlocks;
WLOCK(&db->locks[lock_index]);
if(icl_hash_delete(db->table, key, freeKey, freeUser)){
perror("problema DELETE");
RWUNLOCK(&db->locks[lock_index]);
return false;
}
RWUNLOCK(&db->locks[lock_index]);
return true;
//mai raggiunto
default :
errno = EINVAL;
perror("problema switch op");
return false;
}}
But I can't find the problem, I'm starting to think the problem is in the icl_hash lib.
The problem happens when I'm calling the GET on an element I've just DELETED in the test function.
if(!db_request(db, s , u ,DELETE)){
perror("problema DELETE");
exit(EXIT_FAILURE);
};
//provo a ottenerlo di nuovo
//The error happens here
if(!db_request(db, s , u ,GET)){
perror("GET");
exit(EXIT_FAILURE);
};
The only thing the get does is call this function:
void *
icl_hash_find(icl_hash_t *ht, void* key)
{
icl_entry_t* curr;
unsigned int hash_val;
if(!ht || !key) return NULL;
hash_val = (* ht->hash_function)(key) % ht->nbuckets;
for (curr=ht->buckets[hash_val]; curr != NULL; curr=curr->next)
if ( ht->hash_key_compare(curr->key, key))
return(curr->data);
return NULL;
}
Your invalid access is to memory that is already freed:
Invalid read of size 1
==910== at 0x108DD4: fnv_hash_function (user.c:24)
==910== by 0x108E17: hash (user.c:29)
==910== by 0x109A50: icl_hash_find (icl_hash.c:114)
==910== by 0x1094DB: db_request (user.c:197)
==910== by 0x108D2E: main (tuser.c:65)
==910== Address 0x5416f50 is 0 bytes inside a block of size 15 free'd
==910== at 0x4C2E10B: free (vg_replace_malloc.c:530)
==910== by 0x109152: freeKey (user.c:138)
==910== by 0x109CF2: icl_hash_delete (icl_hash.c:192)
==910== by 0x109796: db_request (user.c:222)
==910== by 0x108CF8: main (tuser.c:59)
==910== Block was alloc'd at
==910== at 0x4C2CEDF: malloc (vg_replace_malloc.c:299)
==910== by 0x108BDC: main (tuser.c:35)
The block was freed in a call to icl_hash_delete() made at line 222 in the function db_request() in the file user.c. The invalid access was made in a call to icl_hash_find() at line 197 in db_request() in user.c. You say that the icl_hash* code is provided to you.
Without the body of the function db_request() is is difficult to be sure what's going on, but there are at least a couple of possibilities.
You've got a dangling pointer to the entry that was deleted, and you should not still be using that.
The code in the icl_hash* functions is mishandling data after a hash record is deleted.
If the provider of the icl_hash.c function is reasonably reliable, it is sensible to assume that the problem is in your code in db_request(). Look hard at lines 197 and 222 in particular, and the variables (pointers) passed to the icl_hash_find() and icl_hash_delete() functions. Look again at the manual page for those functions to see what the rules are.
If you're not sure about the quality of the code in icl_hash.c, you should create yourself a smaller MCVE that creates a hash table, adds some rows, finds some rows, deletes some entries, and does some more finding. This will help you identify whether there's a problem in your code or in the icl_hash.c code.
Since the memory was allocated in main() rather than db_request(), you might have to review what you're doing at that level, but my guess is that you passed that pointer to db_request() and handed ownership of it to the hash table when you added an entry, and the specification of icl_hash_delete() says it will free the memory you handed to the hash table, and you are accidentally still holding a pointer to the now freed memory (the argument to the db_request() function). You have to be very careful to ensure you know who owns what memory — and when that memory has been released.
Valgrind tells you that you have a problem in fnv_hash_function function. In this function you access memory after it has been freed (deallocated) in freeKey. It even tells you that you access it exactly at the beginning of that block of memory. You allocated that memory in main (tuser.c:35). Your program works by accident. It will continue to work as long as the block of memory in question will not end up at the beginning of a memory page and it will be the last block freed on that page - then the page will be (probably - depending on the allocator strategy) unmapped from your process space. After that unmapping if you access it (like in fnv_hash_function) your program will crash exactly at the moment you try access it.
When that block could end up as the first block on the page and be the last one to be freed ? - difficult to say it may happen after any changes that you make to your source code or underlying libraries (including system libraries that you don't control).
I have defined a structure StructA and function StructA createStructA(...) that creates and returns a new StructA. I want to have a function foo() that will explicitly return int error code as well as a new StructA that I want to use outside foo(). So it seems I need pointers to pointers:
int foo(StructA **pA) {
// Allocate some memory:
*pA = malloc(sizeof(StructA)); // (Editor's note: don't cast the return of malloc.)
// check that malloc() didn't error.
assert(*pA);
// Fill out a new StructA with createStructA():
StructA a = createStructA(...);
// return
*pA = &a;
return 0;
}
Why does this code exit with segmentation fault? It appears it is due to malloc as if I comment out all other lines except for malloc line it still breaks with segfault
As the code above may seem unclear, here is MCVE of my problem:
#include <stdio.h>
#include <malloc.h>
typedef struct {
int x;
int y;
} A;
typedef struct {
A a;
int z;
} B;
A makeA() {
return (A) {.x = 1, .y = 2};
}
B makeB(A a1) {
return (B) {.a = a1, .z = 3};
}
void parseA(A **ppa) {
*ppa = malloc(sizeof(A)); // crashes with segfault here
**ppa = makeA();
}
void parseB(B **ppb) {
A **ppa;
parseA(ppa);
// todo make B .. but it's already crashing
}
int main() {
B **ppb;
parseB(ppb);
return 0;
}
*pA = &a set the *pA pointing to a local variable within function foo. When function returns, local variable is out of scope, therefore *pA becomes invalid.
Edit:
Just read your new code. In this line, *ppa = malloc(sizeof(A)); // crashes with segfault here, ppa is not a valid pointer yet, you cannot dereference it by *ppa. Need to do ppa = (A**)malloc(sizeof(A*));first.
Actually, I make a guess here, this is want you want:
void parseA(A **ppa) {
*ppa = (A*)malloc(sizeof(A));
// todo make A, e.g. ppa->x = 1;
}
void parseB(B **ppb) {
A *ppa = NULL;
parseA(&ppa);
// ppa is a valid point now, you can do, e.g. ppa->y=1;
// todo make B
}
In addition to the other corrections, if you will need ppa back in the calling function main, you have no way of returning a value to main. While there is exercise value in what you are doing, your actual goal is anything but clear. It is somewhat of an XY problem, see: What is the XY problem?.
That said, reading between the lines, and to make ppa available back in main, your parseB would have to somehow return a value. You could do so by changing the type to A *parseB (B **ppb).
Further, you seem to have a bit of confusion in whether to declare ppa and ppb as pointers or pointer-to-pointer-to-type. Given your initialization and use, it appears you want a pointer to both ppa and ppb. You would then pass the address of each to the functions parseB and parseA and dereference accordingly to allocate storage for their contents. Doing so, you could craft a parseB similar to:
A *parseB (B **ppb)
{
A *ppa = NULL;
void *tmp = realloc (*ppb, sizeof **ppb);
if (!tmp) {
fprintf (stderr, "error: realloc ppb.\n");
return NULL;
}
*ppb = tmp;
parseA (&ppa);
if (ppa)
**ppb = makeB (*ppa);
return ppa;
}
note: realloc is used for the allocation, because you have no control over whether *ppb has been previously allocated within parseB itself (you do have control over what you send to parseA from parseB so malloc is fine in parseA)
To start this daisy-chain of allocation and assignment of values, your main could be written similar to:
int main ()
{
B *ppb = NULL;
A *ppa = parseB (&ppb);
if (ppa && ppb) {
printf ("ppa->x: %d\nppa->y: %d\n\n"
"ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);
free (ppa);
free (ppb);
}
return 0;
}
Granted, I do not have a clear picture of what you are ultimately attempting to accomplish. So to make use of the values you assign, the pointer level of indirection at the declaration was reduced to make sense of what it looked like you were trying to do. That said, and putting all the pieces together, you could do something similar to the following:
#include <stdio.h>
#include <malloc.h>
typedef struct {
int x;
int y;
} A;
typedef struct {
A a;
int z;
} B;
A makeA ()
{
return (A) {.x = 1,.y = 2};
}
B makeB (A a1)
{
return (B) {.a = a1,.z = 3};
}
void parseA (A **ppa)
{
*ppa = malloc (sizeof (A));
**ppa = makeA ();
}
A *parseB (B **ppb)
{
A *ppa = NULL;
void *tmp = realloc (*ppb, sizeof **ppb);
if (!tmp) {
fprintf (stderr, "error: realloc ppb.\n");
return NULL;
}
*ppb = tmp;
parseA (&ppa);
if (ppa)
**ppb = makeB (*ppa);
return ppa;
}
int main ()
{
B *ppb = NULL;
A *ppa = parseB (&ppb);
if (ppa && ppb) {
printf ("ppa->x: %d\nppa->y: %d\n\n"
"ppb->a.x: %d\nppb->a.y: %d\nppb->z: %d\n",
ppa->x, ppa->y, ppb->a.x, ppb->a.y, ppb->z);
free (ppa); /* if you allocate it, it is up to you to free it */
free (ppb);
}
return 0;
}
Example Use/Output
$ ./bin/structptrissue
ppa->x: 1
ppa->y: 2
ppb->a.x: 1
ppb->a.y: 2
ppb->z: 3
Memory Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to write beyond/outside the bounds of your allocated block of memory, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/structptrissue
==19399== Memcheck, a memory error detector
==19399== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==19399== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==19399== Command: ./bin/structptrissue
==19399==
ppa->x: 1
ppa->y: 2
ppb->a.x: 1
ppb->a.y: 2
ppb->z: 3
==19399==
==19399== HEAP SUMMARY:
==19399== in use at exit: 0 bytes in 0 blocks
==19399== total heap usage: 2 allocs, 2 frees, 20 bytes allocated
==19399==
==19399== All heap blocks were freed -- no leaks are possible
==19399==
==19399== For counts of detected and suppressed errors, rerun with: -v
==19399== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
I am currently working on a project for my school and I am having issues with my code. The purpose of the programm is to implement a plugin manager that search in a directory all "*_plugin.so" file and add a plugin descriptor into a simple linked list.
The C code :
//struct of a single node
typedef
struct _chainon_ {
plugin_descriptor * desc;
struct _chainon_ * next;
} Chainon;
// manager that contains sentry node & number of plugins contained by the list
struct plugin_manager_t {
int nbElts;
Chainon * sentinel;
};
typedef
struct {
const char * m_name; // nom du filtre
const char * m_description; // description de l'effet du filtre
filter_function m_filtre; // fonction de réalisation du filtre
} plugin_descriptor;
Now the register_plugin function, it is called while the programm find a new plugin in the directory, it calls an init_ function that call register_plugin :
void
init_(plugin_manager * pm)
{
register_plugin(pm,
"null_filter",
"Exemple de filtre inutile",
null_filter);
}
and then it is supposed to add the new plug to the list :
void
register_plugin(plugin_manager * pm,
const char filter_name[],
const char filter_description[],
filter_function the_filter)
{
Chainon * n = (Chainon *)malloc(sizeof(Chainon)); //new node that i want to add to the linked list
n->desc = NULL;
n->next = NULL;
n->desc->m_name = filter_name;
n->desc->m_description = filter_description;
n->desc->m_filtre = the_filter;
Chainon * current = pm->sentinel;
for(int i=0;i<pm->nbElts;i++){
current=current->next;
i++;
}
current->next = n;
}
And that is what I am getting with valgrind while I execute this programm :
> ==7022== Invalid write of size 8
> ==7022== at 0x4015A7: register_plugin (pluginmanager.cc:165)
> ==7022== by 0x66E1BDC: init_ (null_filter_plugin.cc:23)
> ==7022== by 0x401483: discover_plugins (pluginmanager.cc:113)
> ==7022== by 0x401187: main (main.cc:17)
> ==7022== Address 0x0 is not stack'd, malloc'd or (recently) free'd
> ==7022==
> ==7022==
> ==7022== Process terminating with default action of signal 11 (SIGSEGV)
> ==7022== Access not within mapped region at address 0x0
> ==7022== at 0x4015A7: register_plugin (pluginmanager.cc:165)
> ==7022== by 0x66E1BDC: init_ (null_filter_plugin.cc:23)
> ==7022== by 0x401483: discover_plugins (pluginmanager.cc:113)
> ==7022== by 0x401187: main (main.cc:17)
> ==7022== If you believe this happened as a result of a stack
> ==7022== overflow in your program's main thread (unlikely but
> ==7022== possible), you can try to increase the size of the
> ==7022== main thread stack using the --main-stacksize= flag.
> ==7022== The main thread stack size used in this run was 8388608.
I am novice at C programming
But I do not understand why I could not initialize "n->desc->name" since I allocated the memory with malloc and then initialized everything to NULL ?
Any help would be appreciate !
Thank you
Your code has several problems, some of them are minor problems and others are causing the posted valgrind output,
Is not really a problem, it's just that you don't need to cast the return value of malloc()
Chainon *n = malloc(sizeof(Chainon));
is ok, no need for the cast.
You need to check that malloc() succeeded, not just assume that it did, under normal situations it will not fail, but in case of failure your program does not handle that, and in case it has some sensitive data that needs to be stored in the hard drive or any other situation where a clean exit is needed, you will cause a lot of problems to the program users, so you should ensure that your program exits cleanly, hence checking the return value of malloc() is a very good thing to do, just check against NULL right after every call to malloc() and handle that according to the situation where the failure occurs.
You don't allocate space for your struct members, every pointer must point to valid memory before dereferencing it, so you must ensure that it does point to valid memory, uninitialized pointers can't be checked so in cases where you are going to initialize the pointer after a possible check, initialize it to NULL.
You do that in one case, but then you dereference the NULL pointer, which is undefined behavior.
Using all the recommendations above, your function has to be re-written like this*
void
register_plugin(plugin_manager * pm,
const char *const filter_name,
const char *const filter_description,
filter_function the_filter)
{
Chainon *chainon;
plugin_descriptor *descriptor;
Chainon *current
int i;
if (pm == NULL)
return;
chainon = malloc(sizeof(*chainon));
if (chainon == NULL)
return;
chainon->next = NULL;
descriptor = malloc(sizeof(*descriptor));
if (descriptor == NULL)
{
free(chainon);
return;
}
chainon->desc = descriptor;
descriptor->m_name = filter_name;
descriptor->m_description = filter_description;
descripotor->m_filtre = the_filter;
current = pm->sentinel;
if (current == NULL)
return;
for(i = 0 ; ((i < pm->nbElts) && (current->next != NULL)) ; ++i)
current = current->next;
current->next = chainon;
}
*Some of the things I changed are not really necessary. I just think it's better that way.
I'm getting an error in valgrind and don't know what is wrong.
The error is:
valgrind output:
==1112== Conditional jump or move depends on uninitialised value(s)
==1112== at 0x402BF0D: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
And it states the problem occurs on line 226:
if(reallocate ==TRUE)
{
char** temp_values = NULL;
temp_values = (char**) realloc(theBoard->_values, theBoard->_size_r*sizeof(char*) );
if(temp_values!=NULL)
{
theBoard->_values = temp_values;
} else
{
reportError(MEM_OUT);
return FALSE;
}
int i = 0;
for (i=0; i<theBoard->_size_r; i++)
{
char* temp_values_c = NULL;
HERE( line 226)-> temp_values_c = realloc(theBoard->_values[i], theBoard->_size_c*sizeof(char) );
if(temp_values_c != NULL)
{
theBoard->_values[i] = temp_values_c;
} else
{
reportError(MEM_OUT);
return FALSE;
}
}
// initialize extra memory
if(row_out_bound)
{
init(theBoard,prev_size_r,0);
}
if(col_out_bound)
{
init(theBoard,0, prev_size_c);
}
}
Why is this happening and how can i fix it?
The problem is theBoard->_values[i] is not initialized since it comes straight from realloc (temp_values = ...).
EDIT
Can you elaborate please?
I thought you'd never ask. The function realloc returns a chunk of memory of the specified size, with no guarantees regarding its contents. So for all practical purposes you should assume anything realloc returns contains garbage. In your code you take that (potential) garbage and on line 226 you tell realloc:
Here's this pointer that's like totally valid and all. It's NULL or I previously obtained it from malloc. Can you realloc it to this size? And that's not true! The actual value contained by theBoard->_values[i] could be anything.
What you want is a loop that does theBoard->_values[i] = NULL, or maybe use malloc instead of realloc on line 226.