CVE-2014-8509: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: The lazy_bdecode function in BitTorrent bootstrap-dht (aka Bootstrap) allows remote attackers to execute arbitrary code via a crafted packet, which triggers an out-of-bounds read, related to "Improper Indexing."
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Published: 2014-10-31T14:55Z
Repository: https://github.com/bittorrent/bootstrap-dht
Language: C++
Files changed: lazy_bdecode.cpp, lazy_entry.hpp
Commit date: 2014-10-23 16:23:01 -0700
Commit message: update version of lazy_bdecode from libtorrent

Diff: diff --git a/lazy_bdecode.cpp b/lazy_bdecode.cpp
index 3bd4080..0f7b292 100644
--- a/lazy_bdecode.cpp
+++ b/lazy_bdecode.cpp
@@ -1,8 +1,8 @@
 /*
 
-Copyright (c) 2008-2012, Arvid Norberg
+Copyright (c) 2008-2014, Arvid Norberg
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
@@ -43,39 +43,66 @@ namespace
 }
 
 namespace libtorrent
 {
 
-#define TORRENT_FAIL_BDECODE(code) \
-	{ \
-		ec = make_error_code(code); \
-		while (!stack.empty()) { \
-			top = stack.back(); \
-			if (top->type() == lazy_entry::dict_t || top->type() == lazy_entry::list_t) top->pop(); \
-			stack.pop_back(); \
-		} \
-		if (error_pos) *error_pos = start - orig_start; \
-		return -1; \
+	namespace
+	{
+		int fail(int* error_pos
+			, std::vector<lazy_entry*>& stack
+			, char const* start
+			, char const* orig_start)
+		{
+			while (!stack.empty()) {
+				lazy_entry* top = stack.back();
+				if (top->type() == lazy_entry::dict_t || top->type() == lazy_entry::list_t)
+				{
+					top->pop();
+					break;
+				}
+				stack.pop_back();
+			}
+			if (error_pos) *error_pos = start - orig_start;
+			return -1;
+		}
 	}
 
-	bool is_digit(char c) { return c >= '0' && c <= '9'; }
+#define TORRENT_FAIL_BDECODE(code) do { ec = make_error_code(code); return fail(error_pos, stack, start, orig_start); } while (false)
 
-	bool is_print(char c) { return c >= 32 && c < 127; }
+	namespace { bool numeric(char c) { return c >= '0' && c <= '9'; } }
 
 	// fills in 'val' with what the string between start and the
 	// first occurance of the delimiter is interpreted as an int.
 	// return the pointer to the delimiter, or 0 if there is a
 	// parse error. val should be initialized to zero
-	char const* parse_int(char const* start, char const* end, char delimiter, boost::int64_t& val)
+	char const* parse_int(char const* start, char const* end, char delimiter
+		, boost::int64_t& val, bdecode_errors::error_code_enum& ec)
 	{
 		while (start < end && *start != delimiter)
 		{
-			if (!is_digit(*start)) { return 0; }
+			if (!numeric(*start))
+			{
+				ec = bdecode_errors::expected_string;
+				return start;
+			}
+			if (val > INT64_MAX / 10)
+			{
+				ec = bdecode_errors::overflow;
+				return start;
+			}
 			val *= 10;
-			val += *start - '0';
+			int digit = *start - '0';
+			if (val > INT64_MAX - digit)
+			{
+				ec = bdecode_errors::overflow;
+				return start;
+			}
+			val += digit;
 			++start;
 		}
+		if (*start != delimiter)
+			ec = bdecode_errors::expected_colon;
 		return start;
 	}
 
 	char const* find_char(char const* start, char const* end, char delimiter)
 	{
@@ -92,11 +119,11 @@ namespace libtorrent
 		if (start == end) return 0;
 
 		std::vector<lazy_entry*> stack;
 
 		stack.push_back(&ret);
-		while (start < end)
+		while (start <= end)
 		{
 			if (stack.empty()) break; // done!
 
 			lazy_entry* top = stack.back();
 
@@ -114,15 +141,23 @@ namespace libtorrent
 					{
 						top->set_end(start);
 						stack.pop_back();
 						continue;
 					}
-					if (!is_digit(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string);
+					if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string);
 					boost::int64_t len = t - '0';
-					start = parse_int(start, end, ':', len);
-					if (start == 0 || start + len + 3 > end || *start != ':')
-						TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon);
+					bdecode_errors::error_code_enum e = bdecode_errors::no_error;
+					start = parse_int(start, end, ':', len, e);
+					if (e)
+						TORRENT_FAIL_BDECODE(e);
+
+					if (start + len + 1 > end)
+						TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
+
+					if (len < 0)
+						TORRENT_FAIL_BDECODE(bdecode_errors::overflow);
+
 					++start;
 					if (start == end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
 					lazy_entry* ent = top->dict_append(start);
 					if (ent == 0) TORRENT_FAIL_BDECODE(boost::system::errc::not_enough_memory);
 					start += len;
@@ -171,17 +206,23 @@ namespace libtorrent
 					stack.pop_back();
 					continue;
 				}
 				default:
 				{
-					if (!is_digit(t))
+					if (!numeric(t))
 						TORRENT_FAIL_BDECODE(bdecode_errors::expected_value);
 
 					boost::int64_t len = t - '0';
-					start = parse_int(start, end, ':', len);
-					if (start == 0 || start + len + 1 > end || *start != ':')
-						TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon);
+					bdecode_errors::error_code_enum e = bdecode_errors::no_error;
+					start = parse_int(start, end, ':', len, e);
+					if (e)
+						TORRENT_FAIL_BDECODE(e);
+					if (start + len + 1 > end)
+						TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
+					if (len < 0)
+						TORRENT_FAIL_BDECODE(bdecode_errors::overflow);
+
 					++start;
 					top->construct_string(start, int(len));
 					stack.pop_back();
 					start += len;
 					continue;
@@ -196,11 +237,14 @@ namespace libtorrent
 	{
 		TORRENT_ASSERT(m_type == int_t);
 		boost::int64_t val = 0;
 		bool negative = false;
 		if (*m_data.start == '-') negative = true;
-		parse_int(negative?m_data.start+1:m_data.start, m_data.start + m_size, 'e', val);
+		bdecode_errors::error_code_enum ec = bdecode_errors::no_error;
+		parse_int(m_data.start + negative
+			, m_data.start + m_size, 'e', val, ec);
+		if (ec) return 0;
 		if (negative) val = -val;
 		return val;
 	}
 
 	lazy_entry* lazy_entry::dict_append(char const* name)
@@ -329,10 +373,17 @@ namespace libtorrent
 		lazy_entry const* e = dict_find(name);
 		if (e == 0 || e->type() != lazy_entry::dict_t) return 0;
 		return e;
 	}
 
+	lazy_entry const* lazy_entry::dict_find_dict(std::string const& name) const
+	{
+		lazy_entry const* e = dict_find(name);
+		if (e == 0 || e->type() != lazy_entry::dict_t) return 0;
+		return e;
+	}
+
 	lazy_entry const* lazy_entry::dict_find_list(char const* name) const
 	{
 		lazy_entry const* e = dict_find(name);
 		if (e == 0 || e->type() != lazy_entry::list_t) return 0;
 		return e;
@@ -348,10 +399,23 @@ namespace libtorrent
 				return &e.val;
 		}
 		return 0;
 	}
 
+	lazy_entry* lazy_entry::dict_find(std::string const& name)
+	{
+		TORRENT_ASSERT(m_type == dict_t);
+		for (int i = 0; i < int(m_size); ++i)
+		{
+			lazy_dict_entry& e = m_data.dict[i];
+			if (name.size() != e.val.m_begin - e.name) continue;
+			if (std::equal(name.begin(), name.end(), e.name))
+				return &e.val;
+		}
+		return 0;
+	}
+
 	lazy_entry* lazy_entry::list_append()
 	{
 		TORRENT_ASSERT(m_type == list_t);
 		TORRENT_ASSERT(m_size <= m_capacity);
 		if (m_capacity == 0)
@@ -490,27 +554,54 @@ namespace libtorrent
 			{
 				bool printable = true;
 				char const* str = e.string_ptr();
 				for (int i = 0; i < e.string_length(); ++i)
 				{
-					using namespace std;
-					if (is_print((unsigned char)str[i])) continue;
+					char c = str[i];
+					if (c >= 32 && c < 127) continue;
 					printable = false;
 					break;
 				}
 				ret += "'";
 				if (printable)
 				{
-					ret += e.string_value();
+					if (single_line && e.string_length() > 30)
+					{
+						ret.append(e.string_ptr(), 14);
+						ret += "...";
+						ret.append(e.string_ptr() + e.string_length()-14, 14);
+					}
+					else
+						ret.append(e.string_ptr(), e.string_length());
 					ret += "'";
 					return ret;
 				}
-				for (int i = 0; i < e.string_length(); ++i)
+				if (single_line && e.string_length() > 20)
 				{
-					char tmp[5];
-					snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
-					ret += tmp;
+					for (int i = 0; i < 9; ++i)
+					{
+						char tmp[5];
+						snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
+						ret += tmp;
+					}
+					ret += "...";
+					for (int i = e.string_length() - 9
+						, len(e.string_length()); i < len; ++i)
+					{
+						char tmp[5];
+						snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
+						ret += tmp;
+					}
+				}
+				else
+				{
+					for (int i = 0; i < e.string_length(); ++i)
+					{
+						char tmp[5];
+						snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
+						ret += tmp;
+					}
 				}
 				ret += "'";
 				return ret;
 			}
 			case lazy_entry::list_t:
@@ -575,10 +666,11 @@ namespace libtorrent
 			"expected colon in bencoded string",
 			"unexpected end of file in bencoded string",
 			"expected value (list, dict, int or string) in bencoded string",
 			"bencoded nesting depth exceeded",
 			"bencoded item count limit exceeded",
+			"integer overflow",
 		};
 		if (ev < 0 || ev >= int(sizeof(msgs)/sizeof(msgs[0])))
 			return "Unknown error";
 		return msgs[ev];
 	}
@@ -587,7 +679,14 @@ namespace libtorrent
 	{
 		static bdecode_error_category bdecode_category;
 		return bdecode_category;
 	}
 
+	namespace bdecode_errors
+	{
+		boost::system::error_code make_error_code(error_code_enum e)
+		{
+			return boost::system::error_code(e, get_bdecode_category());
+		}
+	}
 };
 
diff --git a/lazy_entry.hpp b/lazy_entry.hpp
index 70cec90..0e1bfb6 100644
--- a/lazy_entry.hpp
+++ b/lazy_entry.hpp
@@ -1,8 +1,8 @@
 /*
 
-Copyright (c) 2003-2012, Arvid Norberg
+Copyright (c) 2003-2014, Arvid Norberg
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
@@ -35,10 +35,11 @@ POSSIBILITY OF SUCH DAMAGE.
 
 #include <utility>
 #include <vector>
 #include <string>
 #include <cstring>
+#include <algorithm>
 #include <boost/system/error_code.hpp>
 
 #define TORRENT_EXPORT
 #define TORRENT_EXTRA_EXPORT
 #define TORRENT_ASSERT(x) assert(x)
@@ -134,10 +135,11 @@ namespace libtorrent
 		enum entry_type_t
 		{
 			none_t, dict_t, list_t, string_t, int_t
 		};
 
+		// internal
 		lazy_entry() : m_begin(0), m_len(0), m_size(0), m_capacity(0), m_type(none_t)
 		{ m_data.start = 0; }
 
 		// tells you which specific type this lazy entry has.
 		// See entry_type_t. The type determines which subset of
@@ -154,11 +156,11 @@ namespace libtorrent
 			m_size = length;
 			m_begin = start - 1; // include 'i'
 			m_len = length + 2; // include 'e'
 		}
 
-		// if this is an integer, return the integer value
+		// requires the type to be an integer. return the integer value
 		boost::int64_t int_value() const;
 
 		// internal
 		void construct_string(char const* start, int length);
 
@@ -219,10 +221,13 @@ namespace libtorrent
 		// if this is a dictionary, look for a key ``name``, and return
 		// a pointer to its value, or NULL if there is none.
 		lazy_entry* dict_find(char const* name);
 		lazy_entry const* dict_find(char const* name) const
 		{ return const_cast<lazy_entry*>(this)->dict_find(name); }
+		lazy_entry* dict_find(std::string const& name);
+		lazy_entry const* dict_find(std::string const& name) const
+		{ return const_cast<lazy_entry*>(this)->dict_find(name); }
 		lazy_entry const* dict_find_string(char const* name) const;
 
 		// if this is a dictionary, look for a key ``name`` whose value
 		// is a string. If such key exist, return a pointer to
 		// its value, otherwise NULL.
@@ -233,18 +238,26 @@ namespace libtorrent
 		// is an int. If such key exist, return a pointer to its value,
 		// otherwise NULL.
 		boost::int64_t dict_find_int_value(char const* name, boost::int64_t default_val = 0) const;
 		lazy_entry const* dict_find_int(char const* name) const;
 
+		// these functions require that ``this`` is a dictionary.
+		// (this->type() == dict_t). They look for an element with the
+		// specified name in the dictionary. ``dict_find_dict`` only
+		// finds dictionaries and ``dict_find_list`` only finds lists.
+		// if no key with the corresponding value of the right type is
+		// found, NULL is returned.
 		lazy_entry const* dict_find_dict(char const* name) const;
+		lazy_entry const* dict_find_dict(std::string const& name) const;
 		lazy_entry const* dict_find_list(char const* name) const;
 
 		// if this is a dictionary, return the key value pair at
 		// position ``i`` from the dictionary.
 		std::pair<std::string, lazy_entry const*> dict_at(int i) const;
 
-		// if this is a dictionary, return the number of items in it
+		// requires that ``this`` is a dictionary. return the
+		// number of items in it
 		int dict_size() const
 		{
 			TORRENT_ASSERT(m_type == dict_t);
 			return m_size;
 		}
@@ -260,43 +273,55 @@ namespace libtorrent
 		}
 
 		// internal
 		lazy_entry* list_append();
 
-		// if this is a list, return the item at index ``i``.
+		// requires that ``this`` is a list. return
+		// the item at index ``i``.
 		lazy_entry* list_at(int i)
 		{
 			TORRENT_ASSERT(m_type == list_t);
 			TORRENT_ASSERT(i < int(m_size));
 			return &m_data.list[i];
 		}
 		lazy_entry const* list_at(int i) const
 		{ return const_cast<lazy_entry*>(this)->list_at(i); }
 
+		// these functions require ``this`` to have the type list.
+		// (this->type() == list_t). ``list_string_value_at`` returns
+		// the string at index ``i``. ``list_pstr_at``
+		// returns a pascal_string of the string value at index ``i``.
+		// if the element at ``i`` is not a string, an empty string
+		// is returned.
 		std::string list_string_value_at(int i) const;
 		pascal_string list_pstr_at(int i) const;
+
+		// this function require ``this`` to have the type list.
+		// (this->type() == list_t). returns the integer value at
+		// index ``i``. If the element at ``i`` is not an integer
+		// ``default_val`` is returned, which defaults to 0.
 		boost::int64_t list_int_value_at(int i, boost::int64_t default_val = 0) const;
 
 		// if this is a list, return the number of items in it.
 		int list_size() const
 		{
 			TORRENT_ASSERT(m_type == list_t);
 			return int(m_size);
 		}
 
-		// end points one byte passed last byte in the source
+		// internal: end points one byte passed last byte in the source
 		// buffer backing the bencoded structure.
 		void set_end(char const* end)
 		{
 			TORRENT_ASSERT(end > m_begin);
 			m_len = end - m_begin;
 		}
 		
 		// internal
 		void clear();
 
-		// releases ownership of any memory allocated
+		// internal: releases ownership of any memory allocated
 		void release()
 		{
 			m_data.start = 0;
 			m_size = 0;
 			m_capacity = 0;
@@ -359,13 +384,16 @@ namespace libtorrent
 	{
 		char const* name;
 		lazy_entry val;
 	};
 
-	TORRENT_EXTRA_EXPORT std::string print_entry(lazy_entry const& e
+	// print the bencoded structure in a human-readable format to a stting
+	// that's returned.
+	TORRENT_EXPORT std::string print_entry(lazy_entry const& e
 		, bool single_line = false, int indent = 0);
 
+	// get the ``error_category`` for bdecode errors
 	TORRENT_EXPORT boost::system::error_category& get_bdecode_category();
 
 	namespace bdecode_errors
 	{
 		// libtorrent uses boost.system's ``error_code`` class to represent errors. libtorrent has
@@ -384,20 +412,24 @@ namespace libtorrent
 			expected_value,
 			// bencoded recursion depth limit exceeded
 			depth_exceeded,
 			// bencoded item count limit exceeded
 			limit_exceeded,
+			// integer overflow
+			overflow,
 
 			// the number of error codes
 			error_code_max
 		};
 
 		// hidden
-		inline boost::system::error_code make_error_code(error_code_enum e)
-		{
-			return boost::system::error_code(e, get_bdecode_category());
-		}
+		TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e);
 	}
+
+	TORRENT_EXTRA_EXPORT char const* parse_int(char const* start
+		, char const* end, char delimiter, boost::int64_t& val
+		, bdecode_errors::error_code_enum& ec);
+
 }
 
 #endif
 

Vulnerable code: Copyright (c) 2008-2012, Arvid Norberg
#define TORRENT_FAIL_BDECODE(code) \
	{ \
		ec = make_error_code(code); \
		while (!stack.empty()) { \
			top = stack.back(); \
			if (top->type() == lazy_entry::dict_t || top->type() == lazy_entry::list_t) top->pop(); \
			stack.pop_back(); \
		} \
		if (error_pos) *error_pos = start - orig_start; \
		return -1; \
	bool is_digit(char c) { return c >= '0' && c <= '9'; }
	bool is_print(char c) { return c >= 32 && c < 127; }
	char const* parse_int(char const* start, char const* end, char delimiter, boost::int64_t& val)
			if (!is_digit(*start)) { return 0; }
			val += *start - '0';
		while (start < end)
					if (!is_digit(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string);
					start = parse_int(start, end, ':', len);
					if (start == 0 || start + len + 3 > end || *start != ':')
						TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon);
					if (!is_digit(t))
					start = parse_int(start, end, ':', len);
					if (start == 0 || start + len + 1 > end || *start != ':')
						TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon);
		parse_int(negative?m_data.start+1:m_data.start, m_data.start + m_size, 'e', val);
					using namespace std;
					if (is_print((unsigned char)str[i])) continue;
					ret += e.string_value();
				for (int i = 0; i < e.string_length(); ++i)
					char tmp[5];
					snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
					ret += tmp;
Copyright (c) 2003-2012, Arvid Norberg
		// if this is an integer, return the integer value
		// if this is a dictionary, return the number of items in it
		// if this is a list, return the item at index ``i``.
		// end points one byte passed last byte in the source
		// releases ownership of any memory allocated
	TORRENT_EXTRA_EXPORT std::string print_entry(lazy_entry const& e
		inline boost::system::error_code make_error_code(error_code_enum e)
		{
			return boost::system::error_code(e, get_bdecode_category());
		}
Fixed code: Copyright (c) 2008-2014, Arvid Norberg
	namespace
	{
		int fail(int* error_pos
			, std::vector<lazy_entry*>& stack
			, char const* start
			, char const* orig_start)
		{
			while (!stack.empty()) {
				lazy_entry* top = stack.back();
				if (top->type() == lazy_entry::dict_t || top->type() == lazy_entry::list_t)
				{
					top->pop();
					break;
				}
				stack.pop_back();
			}
			if (error_pos) *error_pos = start - orig_start;
			return -1;
		}
#define TORRENT_FAIL_BDECODE(code) do { ec = make_error_code(code); return fail(error_pos, stack, start, orig_start); } while (false)
	namespace { bool numeric(char c) { return c >= '0' && c <= '9'; } }
	char const* parse_int(char const* start, char const* end, char delimiter
		, boost::int64_t& val, bdecode_errors::error_code_enum& ec)
			if (!numeric(*start))
			{
				ec = bdecode_errors::expected_string;
				return start;
			}
			if (val > INT64_MAX / 10)
			{
				ec = bdecode_errors::overflow;
				return start;
			}
			int digit = *start - '0';
			if (val > INT64_MAX - digit)
			{
				ec = bdecode_errors::overflow;
				return start;
			}
			val += digit;
		if (*start != delimiter)
			ec = bdecode_errors::expected_colon;
		while (start <= end)
					if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string);
					bdecode_errors::error_code_enum e = bdecode_errors::no_error;
					start = parse_int(start, end, ':', len, e);
					if (e)
						TORRENT_FAIL_BDECODE(e);

					if (start + len + 1 > end)
						TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);

					if (len < 0)
						TORRENT_FAIL_BDECODE(bdecode_errors::overflow);

					if (!numeric(t))
					bdecode_errors::error_code_enum e = bdecode_errors::no_error;
					start = parse_int(start, end, ':', len, e);
					if (e)
						TORRENT_FAIL_BDECODE(e);
					if (start + len + 1 > end)
						TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof);
					if (len < 0)
						TORRENT_FAIL_BDECODE(bdecode_errors::overflow);

		bdecode_errors::error_code_enum ec = bdecode_errors::no_error;
		parse_int(m_data.start + negative
			, m_data.start + m_size, 'e', val, ec);
		if (ec) return 0;
	lazy_entry const* lazy_entry::dict_find_dict(std::string const& name) const
	{
		lazy_entry const* e = dict_find(name);
		if (e == 0 || e->type() != lazy_entry::dict_t) return 0;
		return e;
	}

	lazy_entry* lazy_entry::dict_find(std::string const& name)
	{
		TORRENT_ASSERT(m_type == dict_t);
		for (int i = 0; i < int(m_size); ++i)
		{
			lazy_dict_entry& e = m_data.dict[i];
			if (name.size() != e.val.m_begin - e.name) continue;
			if (std::equal(name.begin(), name.end(), e.name))
				return &e.val;
		}
		return 0;
	}

					char c = str[i];
					if (c >= 32 && c < 127) continue;
					if (single_line && e.string_length() > 30)
					{
						ret.append(e.string_ptr(), 14);
						ret += "...";
						ret.append(e.string_ptr() + e.string_length()-14, 14);
					}
					else
						ret.append(e.string_ptr(), e.string_length());
				if (single_line && e.string_length() > 20)
					for (int i = 0; i < 9; ++i)
					{
						char tmp[5];
						snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
						ret += tmp;
					}
					ret += "...";
					for (int i = e.string_length() - 9
						, len(e.string_length()); i < len; ++i)
					{
						char tmp[5];
						snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
						ret += tmp;
					}
				}
				else
				{
					for (int i = 0; i < e.string_length(); ++i)
					{
						char tmp[5];
						snprintf(tmp, sizeof(tmp), "%02x", (unsigned char)str[i]);
						ret += tmp;
					}
			"integer overflow",
	namespace bdecode_errors
	{
		boost::system::error_code make_error_code(error_code_enum e)
		{
			return boost::system::error_code(e, get_bdecode_category());
		}
	}
Copyright (c) 2003-2014, Arvid Norberg
#include <algorithm>
		// internal
		// requires the type to be an integer. return the integer value
		lazy_entry* dict_find(std::string const& name);
		lazy_entry const* dict_find(std::string const& name) const
		{ return const_cast<lazy_entry*>(this)->dict_find(name); }
		// these functions require that ``this`` is a dictionary.
		// (this->type() == dict_t). They look for an element with the
		// specified name in the dictionary. ``dict_find_dict`` only
		// finds dictionaries and ``dict_find_list`` only finds lists.
		// if no key with the corresponding value of the right type is
		// found, NULL is returned.
		lazy_entry const* dict_find_dict(std::string const& name) const;
		// requires that ``this`` is a dictionary. return the
		// number of items in it
		// requires that ``this`` is a list. return
		// the item at index ``i``.
		// these functions require ``this`` to have the type list.
		// (this->type() == list_t). ``list_string_value_at`` returns
		// the string at index ``i``. ``list_pstr_at``
		// returns a pascal_string of the string value at index ``i``.
		// if the element at ``i`` is not a string, an empty string
		// is returned.

		// this function require ``this`` to have the type list.
		// (this->type() == list_t). returns the integer value at
		// index ``i``. If the element at ``i`` is not an integer
		// ``default_val`` is returned, which defaults to 0.
		// internal: end points one byte passed last byte in the source
		// internal: releases ownership of any memory allocated
	// print the bencoded structure in a human-readable format to a stting
	// that's returned.
	TORRENT_EXPORT std::string print_entry(lazy_entry const& e
	// get the ``error_category`` for bdecode errors
			// integer overflow
			overflow,
		TORRENT_EXPORT boost::system::error_code make_error_code(error_code_enum e);

	TORRENT_EXTRA_EXPORT char const* parse_int(char const* start
		, char const* end, char delimiter, boost::int64_t& val
		, bdecode_errors::error_code_enum& ec);