#include #include #include #include /** * Small test program demonstrating suspected bug in xmlRemoveID * function. * * I am confident that this program highlights an error in the xmlRemoveID * function of the valid.c source file of libxml2. It requires the * libxml-ids-error.xml file that should be present with this * source file. It is also included at the end of this file as a * comment. * * * The objectives of this example program are: * * to read the small document included * to modify the id in the sole "myelement" element * to perform a lookup on the new id, which should succeed * to perform a lookup on the old id, which should fail * * */ /** * * You can build this program with gcc, thus: * * gcc `xml2-config --cflags --libs` -ansi libxml-ids-error.c -o libxml-ids-error * * * or, to see xmlUnsetProp to perform incorrectly (due to a call to xmlRemoveID) * * gcc -DWITHOUT_XMLREMOVEID `xml2-config --cflags --libs` -ansi libxml-ids-error.c -o libxml-ids-error * * * */ void myxmlValidityErrorFunc(void *ctx,const char *fmt,...) { if (fmt) { static char p[128]; va_list ap; va_start(ap, fmt); vsnprintf(p,128,fmt,ap); va_end(ap); printf(p); } } int main(int argc,char *argv[]) { xmlDocPtr doc; xmlNodePtr root,myelement; xmlAttrPtr myidattr,mynewidattr,searched_newidattr,searched_myidattr; xmlChar* newretrievedidvalue; xmlValidCtxtPtr ctxt; xmlIDPtr newidptr; /* firstly parse the input file and validate it. */ doc=xmlParseFile("libxml-ids-error.xml"); if (doc==NULL) { printf("Please ensure that libxml-ids-error.xml (that " "should have been\nincluded) is in the present " "working directory when this example\nis run.\n"); return 10; } ctxt=xmlNewValidCtxt(); if (ctxt==NULL) { printf("error: couldn't allocate a xmlValidCtxt\n"); return 40; } ctxt->error=myxmlValidityErrorFunc; ctxt->warning=myxmlValidityErrorFunc; if (xmlValidateDocument(ctxt,doc)) printf("Document is valid\n"); root=xmlDocGetRootElement(doc); myelement=root->children; printf("retreived the 'myelement' element node: myelement->name=\"%s\"\n",(const char*)myelement->name); myidattr=xmlHasProp(myelement,(const xmlChar*)"id"); printf("retreived attribute named \"id\" of myelement: myidattr=%p\n",myidattr); if (myidattr==NULL) { printf("error: id attribute did not exist.\n"); return 20; } /* We have to call xmlRemoveID because xmlSetProp will not * remove the old ID from the document's ids hash table. * try this program with it in and without. if xmlRemoveID * works correctly, it should return success. */ #ifndef WITHOUT_XMLREMOVEID if (xmlRemoveID(doc,myidattr)==0) printf("xmlRemoveID of myidattr returned success\n"); else printf("xmlRemoveID of myidattr returned failure\n"); #else if (xmlUnsetProp(myelement,(const xmlChar*)"id")==0) printf("xmlUnsetProp of myelement, attribute named \"id\" returned success\n"); else printf("xmlUnsetProp of myelement, attribute named \"id\" returned failure\n"); #endif /* what follows now are the kind of events that could lead to a many * errors in the application writer's program from the result of an * incorrectly failed xmlRemoveID call. The application writer may now think * that regardless of the outcome of xmlRemoveID, there is no longer an ID * in our working document that would match myidattr. */ /* xmlSetProp does not change any entries in the ID table, but it will free * the previous value. note that if xmlUnsetProp was used above, it is possible * that this will be at the same address in many memory allocation schemes. */ mynewidattr=xmlSetProp(myelement,(const xmlChar*)"id",(const xmlChar*)"newid"); printf("got newidattr=%p\n",mynewidattr); /* to be absolutely sure that the hash table entry and the * id value are the same, i will fetch the new id from the property name */ newretrievedidvalue = xmlNodeListGetString(doc, mynewidattr->children, 1); if (!newretrievedidvalue) { printf("error retrieving new id value\n"); return 30; } printf("new retrieved ID value=\"%s\"\n",(const char*)newretrievedidvalue); /* have to then add this new ID attribute to the ids hash table */ if ((newidptr=xmlAddID(ctxt,doc,newretrievedidvalue,mynewidattr))) printf("xmlAddID successfully added newmyidattr to the document's ID hash table with key \"%s\", xmlIDPtr=%p\n",(const char*)newretrievedidvalue,newidptr); else printf("xmlAddID failed to add newmyidattr to the document's ID hash table with key \"%s\"\n",(const char*)newretrievedidvalue); xmlFree(newretrievedidvalue); xmlFreeValidCtxt(ctxt); printf("\n\nnow searching for IDs with xmlGetID, now, searching for \"newid\"\nshould return a result and \"myid\" should return nothing:\n\n"); /* search for an attribute with ID "newid" */ printf("searching for xmlAttrPtr with xmlGetID(doc=%p,\"newid\")... ",doc); searched_newidattr=xmlGetID(doc,"newid"); if (searched_newidattr!=NULL) printf("returned xmlAttrPtr %p\n\n",searched_newidattr); else printf("returned null.\n\n"); /* search for an attribute with ID "myid" */ printf("searching for xmlAttrPtr with xmlGetID(doc=%p,\"myid\")... ",doc); searched_myidattr=xmlGetID(doc,"myid"); if (searched_myidattr!=NULL) printf("returned xmlAttrPtr %p, should have returned null\n\n",searched_myidattr); else printf("returned null.\n\n"); xmlFreeDoc(doc); return 0; } /* Content of the libxml-ids-error.xml file, as required by this example: ]> */