For a few days now i have been trying to clean up memory leaks in my system. But this one memory leak has been bugging me.
Problem: Valgrind is reporting a memory leak:
==28423== 10,988 (2,624 direct, 8,364 indirect) bytes in 82 blocks are definitely lost in loss record 405 of 409
==28423== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==28423== by 0x5553780: g_malloc0 (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.1)
==28423== by 0x1B432E56: janus_audiobridge_create_user_secret (janus_audiobridge_room_helper.c:641)
==28423== by 0x1B4250B3: janus_audiobridge_init (janus_audiobridge.c:281)
==28423== by 0x4111BF: main (janus.c:3898)
Heres janus_audiobridge_create_user_secret (janus_audiobridge_room_helper.c:641):
method_user_secret_error_case *janus_audiobridge_create_user_secret(PGconn *conn, janus_audiobridge_user_secret_model *user_secret_model, gboolean insert_in_db) {
JANUS_LOG(LOG_VERB, "Creating user_secret\n");
/* Create the audio bridge secret */
janus_audiobridge_user_secret *user_secret = g_malloc0(sizeof(janus_audiobridge_user_secret));
method_user_secret_error_case *error = g_malloc0(sizeof(method_user_secret_error_case));
if (user_secret_model->user_secret) {
user_secret->user_secret = g_strdup(user_secret_model->user_secret);
} else {
gchar *new_secret = randstring((size_t)100);
user_secret->user_secret = g_strdup(new_secret);
user_secret_model->user_secret = g_strdup(new_secret); // Model is necesarry for saving to database
g_free(new_secret);
}
user_secret->user_ip = g_strdup(user_secret_model->user_ip);
user_secret->created_at = user_secret_model->created_at;
if (insert_in_db) {
// Save to db
int save_err = janus_audiobridge_create_user_secret_db(conn, user_secret_model);
if (save_err == 0) {
JANUS_LOG(LOG_ERR, "Failed to save to database.\n");
g_free(user_secret->user_secret);
g_free(user_secret->user_ip);
g_free(user_secret);
const gchar *error_message = "Error saving to database.\n";
error->error = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
error->error_message = error_message;
return error;
}
}
g_hash_table_insert(user_secrets, g_strdup(user_secret->user_secret), user_secret);
// Prepare response
const gchar *error_message = "";
error->error = 0;
error->error_message = error_message;
error->user_secret = user_secret;
return error;
}
And of course janus_audiobridge_init (janus_audiobridge.c:281):
/* Fetch all user_secrets from database */
const gchar *select_all_user_secrets_query = "SELECT * FROM user_secrets;";
GHashTable *user_secrets_db = user_secrets_query(conn, select_all_user_secrets_query);
// Create user secrets from database
g_hash_table_iter_init(&iter, user_secrets_db);
while (g_hash_table_iter_next(&iter, NULL, &value)) {
janus_audiobridge_user_secret_model *db_user_secret = value;
method_user_secret_error_case *create_resp = janus_audiobridge_create_user_secret(conn, db_user_secret, (gboolean)FALSE);
if (create_resp->error != 0) {
JANUS_LOG(LOG_ERR, "Error: %s\n", create_resp->error_message);
}
g_free(db_user_secret->user_secret);
g_free(db_user_secret->user_ip);
g_free(db_user_secret);
g_free(create_resp);
}
// Free the hashtable of entries from database
g_hash_table_destroy(user_secrets_db);
So my question is following: Why valgrind shows that i am leaking memory even tho, i am freeing it with g_free? The other user_secret struct is stored in HashTable, so i can't free it, because i am using it later.
P.S I don't free user_secret at any place at the code at this time, because i use it consistently in lifetime of my system.
Thanks!
EDIT:
Sorry, i forgot to provide which line is it:
641 line is -
janus_audiobridge_user_secret *user_secret = g_malloc0(sizeof(janus_audiobridge_user_secret));
and 281:
method_user_secret_error_case *create_resp = janus_audiobridge_create_user_secret(conn, db_user_secret, (gboolean)FALSE);
Thanks to #SiggiSv , #n.m and #Attie
After freeing the user secrets on janus_destroy, valgrind stopped reporting that memory leak. So that was more of a problem with me not knowing how valgrind works. Thanks again for everybody who helped.
Here's the code, if somebody finds it usefull:
// Free user secret memory - So Valgrind Doesn't register memory leak
// We do this, because we don't delete user secret in janus logic, and valgrind sees that as a memory leak
GHashTableIter iter;
gpointer value;
g_hash_table_iter_init(&iter, user_secrets);
while (g_hash_table_iter_next(&iter, NULL, &value)) {
janus_audiobridge_user_secret *user_secret = value;
g_free(user_secret->user_secret);
g_free(user_secret->user_ip);
g_free(user_secret);
}
g_hash_table_destroy(user_secrets);
Related
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 am creating a simple dictionary in C using generic linked lists, thus in the process I am using malloc and free.
Anyway, Valgrind sadly doesn't support OS X 10.9, therefore I am using Xcode's Leaks Instrument. However, I have a bit trouble understanding the feedback this tool is providing me. Simpler, from the data output I can't understand if I have leaks or not.
Here is a screenshot of what the tool is telling me:
link to image
Here is the code that is creating the linked list:
typedef struct Element {
struct Element *next;
void *value;
} TElelemt, *TList, **AList;
typedef void (*PrintF) (void *);
int Insert_Elm(AList list, void *value, size_t dimension) {
TList aux = (TList) malloc(sizeof(TElelemt));
if (!aux) {
printf("Allocation error!\n");
return 0;
}
aux->value = malloc(dimension);
if (!aux->value) {
printf("Allocation error!\n");
return 0;
}
memcpy(aux->value, value, dimension);
aux->next = *list;
*list = aux;
return 1;
}
void Delete_Elm(AList list) {
TList elm = *list;
if (!elm) {
return;
}
free(elm->value);
*list = elm->next;
free(elm);
return;
}
void Delete_List(AList list) {
while (*list) {
Delete_Elm(list);
}
return;
}
// In main() I am doing something like this where TWord cuv is allocated in stack:
for (i = 0; i < 1000000; i++) {
Insert_Elm(&list, &cuv, sizeof(TWord));
}
Delete_List(&list);
What is the tool saying and are there any memory leaks?
Your screenshot is showing no memory leaks. In your screenshot the Allocations instruments has graphed your memory usage in blue. If Instruments had detected any memory leaks, it would show them in the graph for the Leaks instrument. But in your screenshot the graph for the Leaks instrument is blank, which means Instruments detected no memory leaks.
One additional thing, your screenshot is showing the statistics for the Allocations instrument. It's telling you the amount of memory your program allocated. Select the Leaks instrument from the instrument list to see the Leaks instrument's statistics. Selecting the Leaks instrument will also tell you whether or not any memory leaks were detected. If you have any leaks, Instruments will list them in the table below the graphs.
Code snippet follows.
Background: Revising a old C windows application to communicate with new instruments (while maintaining as much old code as possible), which requires the addition of new features. In this case I am copying file names from a directory into a 2D array to populate a list of the file names.
While debugging, the program gets to the realloc call (the second realloc, as the first is skipped by the if statement) and then breaks with the error which precedes the code snippet below.
At the time of realloc, WFMLIST has been allocated, with the first element initialized to 0, and NbItemWFMLIST = 1. So my question is, does anybody know why this error might be occurring? The memory allocation and reallocation worked before I added the directory searching and copying components. Is it DLL releated? I have tried many things (suggestions from similar errors on Stackoverflow), including replacing the realloc with a free() and then calloc() and received the same error.
Also, ffd is correctly finding the directory and providing the appropriate string in ffd.cFileName.
Please let me know if I can provide more information. Thanks.
HEAP[vhf.exe]: Heap block at 01068980 modified at 01068989 past
requested size of 1 Windows has triggered a breakpoint in vhf.exe.
This may be due to a corruption of the heap, which indicates a bug in
vhf.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while vhf.exe has focus.
char **WMFLIST=NULL;
long int NbItemWFMLIST = 0;
unsigned int playback_bytes;
WIN32_FIND_DATA ffd; //Added for directory search
LARGE_INTEGER filesize; //
TCHAR szDir[MAX_PATH]; //
TCHAR *pwrkDir;
size_t length_pwrkDir;
HANDLE hFind = INVALID_HANDLE_VALUE;
pwrkDir = (TCHAR *)calloc(5, sizeof(TCHAR));
if(WFMLIST==NULL)
{
WFMLIST=(char **)calloc(NbItemWFMLIST,sizeof(char *));
if(WFMLIST != NULL)
{
WFMLIST[0]=(char *)calloc(13,sizeof(char));
if(WFMLIST[0]==NULL)
{
MessageBox(hWnd,"CALLOC WMLIST[0]==NULL","Memory allocation error",MB_OK);
NbItemWFMLIST=0;
return(0); **error check
}
else
{
NbItemWFMLIST=1;
sprintf_s(&WFMLIST[NbItemWFMLIST-1][0],MAX_PATH,"\0");
}
}
else
{
**error
}
}
else
{
WFMLIST = (char **)realloc((void *) WFMLIST,sizeof(char *));
if(WFMLIST==NULL)
{
**error check
}
else
{
NbItemWFMLIST=1;
sprintf(&WFMLIST[NbItemWFMLIST-1][0],"\0");
}
}
if((tawg->status = GetCurrentDirectory(MAX_PATH,pwrkDir))==SIG_SUCCESS) //Locate the current working directory
{
**Error check
}
sprintf_s(pwrkDir, MAX_PATH, "%s\\Waveforms", pwrkDir); //Append directory with Waveform folder
strcpy(szDir, pwrkDir);
strcat(szDir,"\\*");
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
**error check
}
while (FindNextFile(hFind, &ffd) != 0);
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
**error check
}
else
{
WFMLIST=(char **)realloc((void*)WFMLIST,((NbItemWFMLIST+1)*sizeof(char *)));
if (WFMLIST[NbItemWFMLIST]==NULL)
{
**error
}
else
{
WFMLIST[NbItemWFMLIST]=(char *)calloc(13,sizeof(char));
if (WFMLIST[NbItemWFMLIST]==NULL)
{
**error
}
else
{
sprintf(&WFMLIST[NbItemWFMLIST][0],"%s",ffd.cFileName);
NbItemWFMLIST=NbItemWFMLIST+1;
}
}
}
}
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.
I'm attempting to write a solver for a particular puzzle. It tries to find a solution by trying every possible move one at a time until it finds a solution. The first version tried to solve it depth-first by continually trying moves until it failed, then backtracking, but this turned out to be too slow. I have rewritten it to be breadth-first using a queue structure, but I'm having problems with memory management.
Here are the relevant parts:
int main(int argc, char *argv[])
{
...
int solved = 0;
do {
solved = solver(queue);
} while (!solved && !pblListIsEmpty(queue));
...
}
int solver(PblList *queue) {
state_t *state = (state_t *) pblListPoll(queue);
if (is_solution(state->pucks)) {
print_solution(state);
return 1;
}
state_t *state_cp;
puck new_location;
for (int p = 0; p < puck_count; p++) {
for (dir i = NORTH; i <= WEST; i++) {
if (!rules(state->pucks, p, i)) continue;
new_location = in_dir(state->pucks, p, i);
if (new_location.x != -1) {
state_cp = (state_t *) malloc(sizeof(state_t));
state_cp->move.from = state->pucks[p];
state_cp->move.direction = i;
state_cp->prev = state;
state_cp->pucks = (puck *) malloc (puck_count * sizeof(puck));
memcpy(state_cp->pucks, state->pucks, puck_count * sizeof(puck)); /*CRASH*/
state_cp->pucks[p] = new_location;
pblListPush(queue, state_cp);
}
}
}
free(state->pucks);
return 0;
}
When I run it I get the error:
ice(90175) malloc: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Bus error
The error happens around iteration 93,000.
From what I can tell, the error message is from malloc failing, and the bus error is from the memcpy after it.
I have a hard time believing that I'm running out of memory, since each game state is only ~400 bytes. Yet that does seem to be what's happening, seeing as the activity monitor reports that it is using 3.99GB before it crashes. I'm using http://www.mission-base.com/peter/source/ for the queue structure (it's a linked list).
Clearly I'm doing something dumb. Any suggestions?
Check the result of malloc. If it's NULL, you might want to print out the length of that queue.
Also, the code snippet you posted didn't include any frees...
You need to free() the memory you've allocated manually after you're done with it; dynamic memory doesn't just "free itself"