libxml2iOS4에서 xmlFreeDoc로 인한 프로그램 Crash 해결 방법

4666 단어 iOSlibxml
최근에 iOS 프로그램을 개발할 때 웹서비스를 호출할 때 iOS에 내장된libxml2를 사용하여 DOM 트리의 조작 라이브러리로 사용했다. 공식 코드의 참고에 따라 DOM을 만드는 코드를 썼고 일부 부분은 다음과 같다.
xmlNodePtr generateSoap11MessageWrapper(void)
{
	// create Document with Default version
	const xmlDocPtr pDoc = xmlNewDoc(NULL);
	{
		// force version and encoding
		pDoc->version = _XS"1.0";
		pDoc->encoding = _XS"UTF-8";
	}
	// create Root-Element
	const xmlNodePtr pRoot = xmlNewNode(NULL, _XS"Envelope");
	{
		// attach namespace definition to @pRoot->nsDef.
		xmlNewNs(pRoot, _XS"http://www.w3.org/2001/XMLSchema-instance", _XS"xsi");
		xmlNewNs(pRoot, _XS"http://www.w3.org/2001/XMLSchema", _XS"xsd");
		const xmlNsPtr pNsSoap = xmlNewNs(pRoot, _XS"http://schemas.xmlsoap.org/soap/envelope/", _XS"soap");
		
		// set the ns as the node namespace
		xmlSetNs(pRoot, pNsSoap);
	}
	
	// set @pRoot as Document's root
	xmlDocSetRootElement(pDoc, pRoot);
	
	// assign Root-Element to a readable name (Envelope node)
	const xmlNodePtr pEnvelope = pRoot;
	
	// create no content Body node (inherit parent, @pEnvelope, namespace by using NULL in namespace)
	const xmlNodePtr pBody = xmlNewChild(pEnvelope, NULL, _XS"Body", NULL);
	
	//	xmlFreeDoc(pDoc);	// dont free the returning doc
	//	xmlMemoryDump();	// debug memory for regression tests
	
	return pBody;
}
이상의 코드는libxml2 홈페이지를 참조하는 예입니다.http://xmlsoft.org/examples/tree2.c
왜 놓지 않았는지 의문이 있을 수 있습니다. 이 함수는 대상을 만드는 것을 책임지고, 놓기는 호출자가 처리하며, 그것을 호출하는 것은 ObjectiveC 스타일의 방법입니다.
+ (NSURLRequest*)generateSoap11Request:(WebServiceEnvelope*)envelope
{
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:envelope.serviceUrl];
	
	const xmlNodePtr pBody= generateSoap11MessageWrapper();
	{
		// create soap action node.
		const xmlNodePtr pAction = xmlNewChild(pBody, NULL, [envelope.action toXmlChar], NULL);
		{
			xmlNsPtr pNs = xmlNewNs(pAction, [envelope.namespace toXmlChar], NULL);
			xmlSetNs(pAction, pNs);
		}
		
		// process parameters
		for (NSString* key in [envelope.paramters keyEnumerator])
		{
			NSString* value = [envelope.paramters valueForKey:key];
			
			xmlNewTextChild(pAction, NULL, [key toXmlChar], [value toXmlChar]);
		}
	}
	
	NSString *soapAction = [NSString stringWithFormat:@"%@%@", envelope.namespace, envelope.action];
	NSString* soapMessage = xmlDocToNSString(pBody->doc);
	NSString* messageLength = [NSString stringWithFormat:@"%d", soapMessage.length];
	
	[request addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
	[request addValue:messageLength forHTTPHeaderField:@"Content-Length"];
	[request addValue:soapAction forHTTPHeaderField:@"SOAPAction"];
	[request setHTTPMethod:@"POST"];
	[request setHTTPBody: [soapMessage dataUsingEncoding:NSUnicodeStringEncoding]];
	
	// release doc
	xmlFreeDoc(pBody->doc);
	
	return request;
}

문제가 생겼다!
4.3의 시뮬레이터에서 실행되고 특별한 상황은 없습니다. 바로generateSoap11Request를 호출할 때 시뮬레이터가 나타났습니다.
Application(768,0xa0c50540) malloc: *** error for object 0xb1e94: pointer being free was not allocated
*** set a breakpoint in malloc_error_break to debug
보아하니 문제가 없다. 프로그램이 정상적으로 작동할 수 있으면 상관없다.
결국
아이패드에 올라가서 뛰기(아이패드는 4.2) 첫 번째 인터페이스에서 데이터를 요청하면 틀렸어요!
xmlDoc를 놓는 줄에 커서가 멈추었습니다
xmlFreeDoc(pBody->doc);
인터럽트는 SIGABRT가 일으킨 것으로 오류 정보는 시뮬레이터와 같다!
Pointer being free was not allocated Google을 한 바퀴 돌린 후 기본적으로mallocHistory의, 그리고 Xcode4.3의 (lldb) 알림부호에는 마지막으로 잘못된 함수명과 플랫폼을 사용하지 않았습니다. ("xmlFreeDoc iOS 4") 드디어 Google에서 maillist를 찾았습니다. 그 안에 문제가 명확하게 설명되어 있습니다.
원본 주소:http://mail.gnome.org/archives/xml/2010-October/msg00031.html
xmlFreeDoc does a xmlFree on doc->encoding, but you set it to a string
which was not dynamically allocated. In effect, you are calling
xmlFree on the "utf-8" string literal. This is wrong. You need to do
at least this:

doc->encoding = xmlStrDup("utf-8");
의 뜻은 다음과 같다. xmlFreeDoc는 doc->encoding을 방출하고 문서를 초기화할 때 유사한doc->encoding=BAD 를 사용한다.CAST'UTF-8'이런 방식을 초기화하면 창고에 있는 메모리(C++에서 delete'literal'같은 동작을 방출하는 것과 같다)를 방출하는 것과 같다. 그러면 오류가 발생할 수 있기 때문에 우리는 메모리를 동적 신청해야 한다. 이 경우libxml은 이미 나를 도와주었다. xmlStrdup을 사용하면 텍스트를 복사하고 xmlChar* 형식으로 변환할 수 있다. 즉,
doc->encoding = xmlStrDup("utf-8");

위에서 보듯이 doc의 속성을 설정하려면 xmlStrdup을 사용하여 문자열을 한 번 복사하면 됩니다.
주: 당분간은 xmlDoc 내 대상만 이런 문제가 있을 것 같은데, xmlNode에서는 이름 내용과 같은 것들이 xmlNewChild를 통해 새로 만든 하위 노드를 통해 상수 문자열을 직접 전송할 수 있지만 xmlFreeDoc에서는 문제가 없습니다.

좋은 웹페이지 즐겨찾기