[xml] Multithreaded library, xmlInitParser and valgrind
- From: Christian Ferrari <camauz yahoo com>
- To: xml gnome org
- Subject: [xml] Multithreaded library, xmlInitParser and valgrind
- Date: Thu, 16 Dec 2010 21:55:34 +0000 (GMT)
Dear All,
I'm developing a multithreaded library and I'm using libxml2.
The code is worked as designed, but valgrind tool detects a small memory leak (24 byte) if
xmlInitParser()/xmlCleanupParser() is called more than once from threaded functions.
This is the description of the environment:
uname -a
Linux ubuntu 2.6.24-28-server
libxml2 version: 2.6.31.dfsg-2ubuntu1.5
valgrind version: valgrind-3.3.0-Debian
This code does NOT exploit the memory leak and this is in accordance to the note explained at this URL:
http://xmlsoft.org/threads.html
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <libxml/parser.h>
char *XML_STRING="<?xml version=\"1.0\" encoding=\"UTF-8\" ?><foo></foo>";
void *thread1(void *parm);
void *thread2(void *parm);
int main(int argc, char *argv[])
{
pthread_t t1, t2;
xmlInitParser();
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
xmlCleanupParser();
return 0;
}
void *thread1(void *parm)
{
xmlDocPtr doc;
printf("[1] --- begin ---\n");
printf("[1] xmlReadMemory()\n");
doc = xmlReadMemory(XML_STRING, strlen(XML_STRING), "buffer.xml", NULL, 0);
printf("[1] xmlFreeDoc()\n");
xmlFreeDoc(doc);
printf("[1] sleep()\n");
sleep(2);
printf("[1] --- end ---\n");
return NULL;
}
void *thread2(void *parm)
{
xmlDocPtr doc;
printf("[2] --- begin ---\n");
printf("[2] sleep()\n");
sleep(1);
printf("[2] xmlReadMemory()\n");
doc = xmlReadMemory(XML_STRING, strlen(XML_STRING), "buffer.xml", NULL, 0);
printf("[2] xmlFreeDoc()\n");
xmlFreeDoc(doc);
printf("[2] --- end ---\n");
return NULL;
}
valgrind --leak-check=full --show-reachable=yes --num-callers=1000 a.out
==21489== Memcheck, a memory error detector.
==21489== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==21489== Using LibVEX rev 1804, a library for dynamic binary translation.
==21489== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==21489== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
==21489== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==21489== For more details, rerun with: -v
==21489==
[1] --- begin ---
[2] --- begin ---
[2] sleep()
[1] xmlReadMemory()
[1] xmlFreeDoc()
[1] sleep()
[2] xmlReadMemory()
[2] xmlFreeDoc()
[2] --- end ---
[1] --- end ---
[1] --- begin ---
[1] xmlReadMemory()
[1] xmlFreeDoc()
[1] sleep()
[2] --- begin ---
[2] sleep()
[2] xmlReadMemory()
[2] xmlFreeDoc()
[2] --- end ---
[1] --- end ---
==21489==
==21489== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from 1)
==21489== malloc/free: in use at exit: 0 bytes in 0 blocks.
==21489== malloc/free: 130 allocs, 130 frees, 52,826 bytes allocated.
==21489== For counts of detected errors, rerun with: -v
==21489== All heap blocks were freed -- no leaks are possible.
Moving xmlInitParser() and xmlCleanupParser() inside a thread, EXPLOITS the memory leak IF AND ONLY IF the
xmlInitParser() is called after xmlCleanupParser().
This code DOES exploit the memory leak:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <libxml/parser.h>
char *XML_STRING="<?xml version=\"1.0\" encoding=\"UTF-8\" ?><foo></foo>";
void *thread1(void *parm);
void *thread2(void *parm);
int main(int argc, char *argv[])
{
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
void *thread1(void *parm)
{
xmlDocPtr doc;
printf("[1] --- begin ---\n");
printf("[1] xmlInitParser()\n");
xmlInitParser();
printf("[1] xmlReadMemory()\n");
doc = xmlReadMemory(XML_STRING, strlen(XML_STRING), "buffer.xml", NULL, 0);
printf("[1] xmlFreeDoc()\n");
xmlFreeDoc(doc);
printf("[1] sleep()\n");
sleep(2);
printf("[1] xmlCleanupParser()\n");
xmlCleanupParser();
printf("[1] --- end ---\n");
return NULL;
}
void *thread2(void *parm)
{
xmlDocPtr doc;
printf("[2] --- begin ---\n");
printf("[2] sleep()\n");
sleep(1);
printf("[2] xmlReadMemory()\n");
doc = xmlReadMemory(XML_STRING, strlen(XML_STRING), "buffer.xml", NULL, 0);
printf("[2] xmlFreeDoc()\n");
xmlFreeDoc(doc);
printf("[2] --- end ---\n");
return NULL;
}
valgrind --leak-check=full --show-reachable=yes --num-callers=1000 a.out
[1] --- begin ---
[1] xmlInitParser()
[1] xmlReadMemory()
[1] xmlFreeDoc()
[1] sleep()
[2] --- begin ---
[2] sleep()
[2] xmlReadMemory()
[2] xmlFreeDoc()
[2] --- end ---
[1] xmlCleanupParser()
[1] --- end ---
==21513==
==21513== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from 1)
==21513== malloc/free: in use at exit: 24 bytes in 1 blocks.
==21513== malloc/free: 149 allocs, 148 frees, 52,380 bytes allocated.
==21513== For counts of detected errors, rerun with: -v
==21513== searching for pointers to 1 not-freed blocks.
==21513== checked 129,132 bytes.
==21513==
==21513== 24 bytes in 1 blocks are definitely lost in loss record 1 of 1
==21513== at 0x4022AB8: malloc (vg_replace_malloc.c:207)
==21513== by 0x40D8534: xmlNewMutex (in /usr/lib/libxml2.so.2.6.31)
==21513== by 0x40D7EC6: xmlInitGlobals (in /usr/lib/libxml2.so.2.6.31)
==21513== by 0x40D80C5: xmlInitializeGlobalState (in /usr/lib/libxml2.so.2.6.31)
==21513== by 0x40D85FD: xmlGetGlobalState (in /usr/lib/libxml2.so.2.6.31)
==21513== by 0x40D75BB: __xmlGenericError (in /usr/lib/libxml2.so.2.6.31)
==21513== by 0x406CCA4: xmlInitParser (in /usr/lib/libxml2.so.2.6.31)
==21513== by 0x8048773: thread1 (case0033.c:61)
==21513== by 0x40314FA: start_thread (in /lib/tls/i686/cmov/libpthread-2.7.so)
==21513== by 0x423BF5D: clone (in /lib/tls/i686/cmov/libc-2.7.so)
==21513==
==21513== LEAK SUMMARY:
==21513== definitely lost: 24 bytes in 1 blocks.
==21513== possibly lost: 0 bytes in 0 blocks.
==21513== still reachable: 0 bytes in 0 blocks.
==21513== suppressed: 0 bytes in 0 blocks.
Removing the second call to xmlInitParser() and xmlCleanupParser() removes the memory leak.
This code does NOT exploit the memory leak:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <libxml/parser.h>
char *XML_STRING="<?xml version=\"1.0\" encoding=\"UTF-8\" ?><foo></foo>";
void *thread1(void *parm);
void *thread2(void *parm);
int main(int argc, char *argv[])
{
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
void *thread1(void *parm)
{
xmlDocPtr doc;
printf("[1] --- begin ---\n");
printf("[1] xmlInitParser()\n");
xmlInitParser();
printf("[1] xmlReadMemory()\n");
doc = xmlReadMemory(XML_STRING, strlen(XML_STRING), "buffer.xml", NULL, 0);
printf("[1] xmlFreeDoc()\n");
xmlFreeDoc(doc);
printf("[1] sleep()\n");
sleep(2);
printf("[1] xmlCleanupParser()\n");
xmlCleanupParser();
printf("[1] --- end ---\n");
return NULL;
}
void *thread2(void *parm)
{
xmlDocPtr doc;
printf("[2] --- begin ---\n");
printf("[2] sleep()\n");
sleep(1);
printf("[2] xmlReadMemory()\n");
doc = xmlReadMemory(XML_STRING, strlen(XML_STRING), "buffer.xml", NULL, 0);
printf("[2] xmlFreeDoc()\n");
xmlFreeDoc(doc);
printf("[2] --- end ---\n");
return NULL;
}
valgrind --leak-check=full --show-reachable=yes --num-callers=1000 a.out
==21540== Memcheck, a memory error detector.
==21540== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==21540== Using LibVEX rev 1804, a library for dynamic binary translation.
==21540== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==21540== Using valgrind-3.3.0-Debian, a dynamic binary instrumentation framework.
==21540== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==21540== For more details, rerun with: -v
==21540==
[1] --- begin ---
[2] --- begin ---
[2] sleep()
[1] xmlInitParser()
[1] xmlReadMemory()
[1] xmlFreeDoc()
[1] sleep()
[2] xmlReadMemory()
[2] xmlFreeDoc()
[2] --- end ---
[1] xmlCleanupParser()
[1] --- end ---
==21540==
==21540== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from 1)
==21540== malloc/free: in use at exit: 0 bytes in 0 blocks.
==21540== malloc/free: 75 allocs, 75 frees, 26,314 bytes allocated.
==21540== For counts of detected errors, rerun with: -v
==21540== All heap blocks were freed -- no leaks are possible.
A 24 bytes memory leak is not a big issue, but it is annoying me I am not able to remove the leak: my library
is passive and I have no "clean way" to force the developer to call xmlInitParser() and xmlCleanupParser() in
its main program because I am implementing "Distributed Transaction Processing: the TX (Transaction
Demarcation) specification" and there is no a good hook for a main based initialization: the library
initialization may happen from any thread.
Any hint is welcomed.
Regards
Ch.F.
-------------------------------------------------------------------
Decent workarounds outperform poor solutions
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]