Parcourir la source

* apt-pkg/contrib/error.cc:
- ensure that va_list is not invalid in second try

David Kalnischkies il y a 15 ans
Parent
commit
38f297033f
4 fichiers modifiés avec 120 ajouts et 94 suppressions
  1. 77 92
      apt-pkg/contrib/error.cc
  2. 3 2
      apt-pkg/contrib/error.h
  3. 8 0
      debian/changelog
  4. 32 0
      test/libapt/globalerror_test.cc

+ 77 - 92
apt-pkg/contrib/error.cc

@@ -58,124 +58,109 @@
 // GlobalError::GlobalError - Constructor				/*{{{*/
 GlobalError::GlobalError() : PendingFlag(false) {}
 									/*}}}*/
-// GlobalError::FatalE - Get part of the error string from errno	/*{{{*/
-bool GlobalError::FatalE(const char *Function,const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return InsertErrno(FATAL, Function, Description, args);
-}
-									/*}}}*/
-// GlobalError::Errno - Get part of the error string from errno		/*{{{*/
-bool GlobalError::Errno(const char *Function,const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return InsertErrno(ERROR, Function, Description, args);
-}
-									/*}}}*/
-// GlobalError::WarningE - Get part of the warning string from errno	/*{{{*/
-bool GlobalError::WarningE(const char *Function,const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return InsertErrno(WARNING, Function, Description, args);
-}
-									/*}}}*/
-// GlobalError::NoticeE - Get part of the notice string from errno	/*{{{*/
-bool GlobalError::NoticeE(const char *Function,const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return InsertErrno(NOTICE, Function, Description, args);
-}
-									/*}}}*/
-// GlobalError::DebugE - Get part of the debug string from errno	/*{{{*/
-bool GlobalError::DebugE(const char *Function,const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return InsertErrno(DEBUG, Function, Description, args);
+// GlobalError::FatalE, Errno, WarningE, NoticeE and DebugE - Add to the list/*{{{*/
+#define GEMessage(NAME, TYPE) \
+bool GlobalError::NAME (const char *Function, const char *Description,...) { \
+	va_list args; \
+	size_t msgSize = 400; \
+	int const errsv = errno; \
+	while (true) { \
+		va_start(args,Description); \
+		if (InsertErrno(TYPE, Function, Description, args, errsv, msgSize) == false) \
+			break; \
+		va_end(args); \
+	} \
+	return false; \
 }
+GEMessage(FatalE, FATAL)
+GEMessage(Errno, ERROR)
+GEMessage(WarningE, WARNING)
+GEMessage(NoticeE, NOTICE)
+GEMessage(DebugE, DEBUG)
+#undef GEMessage
 									/*}}}*/
 // GlobalError::InsertErrno - Get part of the errortype string from errno/*{{{*/
 bool GlobalError::InsertErrno(MsgType const &type, const char *Function,
 				const char *Description,...) {
 	va_list args;
-	va_start(args,Description);
-	return InsertErrno(type, Function, Description, args);
+	size_t msgSize = 400;
+	int const errsv = errno;
+	while (true) {
+		va_start(args,Description);
+		if (InsertErrno(type, Function, Description, args, errsv, msgSize) == false)
+			break;
+		va_end(args);
+	}
+	return false;
 }
 									/*}}}*/
 // GlobalError::InsertErrno - formats an error message with the errno	/*{{{*/
 bool GlobalError::InsertErrno(MsgType type, const char* Function,
-			      const char* Description, va_list &args) {
-	int const errsv = errno;
-	char* S = (char*) malloc(400);
-	size_t const Ssize = snprintf(S, 400, "%s - %s (%i: %s)", Description,
-				      Function, errsv, strerror(errsv)) + 1;
-
-	if (Ssize > 400) {
-		free(S);
-		S = (char*) malloc(Ssize);
-		snprintf(S, Ssize, "%s - %s (%i: %s)", Description,
-			 Function, errsv, strerror(errsv));
+			      const char* Description, va_list &args,
+			      int const errsv, size_t &msgSize) {
+	char* S = (char*) malloc(msgSize);
+	int const n = snprintf(S, msgSize, "%s - %s (%i: %s)", Description,
+			       Function, errsv, strerror(errsv));
+	if (n > -1 && ((unsigned int) n) < msgSize);
+	else {
+		if (n > -1)
+			msgSize = n + 1;
+		else
+			msgSize *= 2;
+		return true;
 	}
 
-	bool const geins = Insert(type, S, args);
+	bool const geins = Insert(type, S, args, msgSize);
 	free(S);
 	return geins;
 }
 									/*}}}*/
-// GlobalError::Fatal - Add a fatal error to the list			/*{{{*/
-bool GlobalError::Fatal(const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return Insert(FATAL, Description, args);
-}
-									/*}}}*/
-// GlobalError::Error - Add an error to the list			/*{{{*/
-bool GlobalError::Error(const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return Insert(ERROR, Description, args);
-}
-									/*}}}*/
-// GlobalError::Warning - Add a warning to the list			/*{{{*/
-bool GlobalError::Warning(const char *Description,...) {
-	va_list args;
-	va_start(args,Description);
-	return Insert(WARNING, Description, args);
-}
-									/*}}}*/
-// GlobalError::Notice - Add a notice to the list			/*{{{*/
-bool GlobalError::Notice(const char *Description,...)
-{
-	va_list args;
-	va_start(args,Description);
-	return Insert(NOTICE, Description, args);
-}
-									/*}}}*/
-// GlobalError::Debug - Add a debug to the list				/*{{{*/
-bool GlobalError::Debug(const char *Description,...)
-{
-	va_list args;
-	va_start(args,Description);
-	return Insert(DEBUG, Description, args);
+// GlobalError::Fatal, Error, Warning, Notice and Debug - Add to the list/*{{{*/
+#define GEMessage(NAME, TYPE) \
+bool GlobalError::NAME (const char *Description,...) { \
+	va_list args; \
+	size_t msgSize = 400; \
+	while (true) { \
+		va_start(args,Description); \
+		if (Insert(TYPE, Description, args, msgSize) == false) \
+			break; \
+		va_end(args); \
+	} \
+	return false; \
 }
+GEMessage(Fatal, FATAL)
+GEMessage(Error, ERROR)
+GEMessage(Warning, WARNING)
+GEMessage(Notice, NOTICE)
+GEMessage(Debug, DEBUG)
+#undef GEMessage
 									/*}}}*/
 // GlobalError::Insert - Add a errotype message to the list		/*{{{*/
 bool GlobalError::Insert(MsgType const &type, const char *Description,...)
 {
 	va_list args;
-	va_start(args,Description);
-	return Insert(type, Description, args);
+	size_t msgSize = 400;
+	while (true) {
+		va_start(args,Description);
+		if (Insert(type, Description, args, msgSize) == false)
+			break;
+		va_end(args);
+	}
+	return false;
 }
 									/*}}}*/
 // GlobalError::Insert - Insert a new item at the end			/*{{{*/
 bool GlobalError::Insert(MsgType type, const char* Description,
-			 va_list &args) {
-	char* S = (char*) malloc(400);
-	size_t const Ssize = vsnprintf(S, 400, Description, args) + 1;
-
-	if (Ssize > 400) {
-		free(S);
-		S = (char*) malloc(Ssize);
-		vsnprintf(S, Ssize, Description, args);
+			 va_list &args, size_t &msgSize) {
+	char* S = (char*) malloc(msgSize);
+	int const n = vsnprintf(S, msgSize, Description, args);
+	if (n > -1 && ((unsigned int) n) < msgSize);
+	else {
+		if (n > -1)
+			msgSize = n + 1;
+		else
+			msgSize *= 2;
+		return true;
 	}
 
 	Item const m(S, type);

+ 3 - 2
apt-pkg/contrib/error.h

@@ -307,9 +307,10 @@ private:								/*{{{*/
 	std::list<MsgStack> Stacks;
 
 	bool InsertErrno(MsgType type, const char* Function,
-			 const char* Description, va_list &args);
+			 const char* Description, va_list &args,
+			 int const errsv, size_t &msgSize);
 	bool Insert(MsgType type, const char* Description,
-			 va_list &args);
+			 va_list &args, size_t &msgSize);
 									/*}}}*/
 };
 									/*}}}*/

+ 8 - 0
debian/changelog

@@ -1,3 +1,11 @@
+apt (0.8.11.4) UNRELEASED; urgency=low
+
+  [ David Kalnischkies ]
+  * apt-pkg/contrib/error.cc:
+    - ensure that va_list is not invalid in second try
+
+ -- David Kalnischkies <kalnischkies@gmail.com>  Tue, 15 Feb 2011 13:09:57 +0100
+
 apt (0.8.11.3) unstable; urgency=low
 
   * apt-pkg/contrib/fileutl.cc:

+ 32 - 0
test/libapt/globalerror_test.cc

@@ -2,6 +2,7 @@
 
 #include "assert.h"
 #include <string>
+#include <errno.h>
 
 int main(int argc,char *argv[])
 {
@@ -73,5 +74,36 @@ int main(int argc,char *argv[])
 	equals(text, "A Warning");
 	equals(_error->empty(), true);
 
+	errno = 0;
+	equals(_error->Errno("errno", "%s horrible %s %d times", "Something", "happend", 2), false);
+	equals(_error->empty(), false);
+	equals(_error->PendingError(), true);
+	equals(_error->PopMessage(text), true);
+	equals(_error->PendingError(), false);
+	equals(text, "Something horrible happend 2 times - errno (0: Success)");
+	equals(_error->empty(), true);
+
+	std::string longText;
+	for (size_t i = 0; i < 500; ++i)
+		longText.append("a");
+	equals(_error->Error("%s horrible %s %d times", longText.c_str(), "happend", 2), false);
+	equals(_error->PopMessage(text), true);
+	equals(text, std::string(longText).append(" horrible happend 2 times"));
+
+	equals(_error->Errno("errno", "%s horrible %s %d times", longText.c_str(), "happend", 2), false);
+	equals(_error->PopMessage(text), true);
+	equals(text, std::string(longText).append(" horrible happend 2 times - errno (0: Success)"));
+
+	equals(_error->Warning("Репозиторий не обновлён и будут %d %s", 4, "test"), false);
+	equals(_error->PopMessage(text), false);
+	equals(text, "Репозиторий не обновлён и будут 4 test");
+
+	longText.clear();
+	for (size_t i = 0; i < 50; ++i)
+		longText.append("РезийбёбAZ");
+	equals(_error->Warning(longText.c_str()), false);
+	equals(_error->PopMessage(text), false);
+	equals(text, longText);
+
 	return 0;
 }