Browse Source

代码可以不崩溃运行ResDataObject首次提交

lwk 1 day ago
parent
commit
a209919d91
3 changed files with 151 additions and 99 deletions
  1. 2 1
      ResDataObject/CMakeLists.txt
  2. 137 78
      ResDataObject/ResDataObject.cpp
  3. 12 20
      ResDataObject/ResDataObject.h

+ 2 - 1
ResDataObject/CMakeLists.txt

@@ -5,7 +5,8 @@ project(ResDataObject VERSION 1.0.0 LANGUAGES CXX)
 # set(CMAKE_CXX_STANDARD 17)
 # set(CMAKE_CXX_STANDARD_REQUIRED ON)
 # set(CMAKE_CXX_EXTENSIONS OFF)
-
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -g")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
 # 配置输出目录
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

+ 137 - 78
ResDataObject/ResDataObject.cpp

@@ -220,66 +220,86 @@ bool ParsePtToDataObject(ResDataObject &obj,ptree &pt)
 
 }
 
-bool ParseDataObjectToPt(ptree& pt, ResDataObject& obj)
-{
-	//std::cout << "[ParseDataObjectToPt] Entering function, object size: " << obj.size() << std::endl;
-	const size_t objSize = obj.size();
-
-	for (size_t i = 0; i < objSize; i++)
-	{
-		//std::cout << "[ParseDataObjectToPt] Processing element #" << i
-			//<< ", key: " << obj.GetKey(i) << std::endl;
-		if (i >= obj.size()) {
-			std::cerr << "Index " << i << " out of range (size=" << obj.size() << ")" << std::endl;
-			return false;
+bool ParseDataObjectToPt(ptree& pt, ResDataObject& obj) {
+	auto recursive_parse = [&](auto& self, ptree& current_pt, ResDataObject& current_obj, int depth) -> bool {
+		// 增强的空对象检查
+		if (!current_obj.IsObject() || current_obj.size() == 0) {
+			return true;
 		}
 
-		const char* key = obj.GetKey(i);
-		if (!key || *key == '\0') { // 拒绝空指针或空字符串键
-			std::cerr << "Invalid key at index " << i << std::endl;
+		if (depth > 100) { // 降低深度限制到更安全的100层
+			std::cerr << "Recursion depth limit exceeded (100)" << std::endl;
 			return false;
 		}
 
-		if (obj[i].size() > 0)
-		{
-			//object
-			//std::cout << "[ParseDataObjectToPt] Element #" << i
-				//<< " is a nested object, size: " << obj[i].size() << std::endl;
-
-			ptree subpt;
-			if (ParseDataObjectToPt(subpt, obj[i]) == false)
-			{
-				std::cerr << "[ParseDataObjectToPt] ERROR: Failed to parse nested object at index " << i << std::endl;
+		const size_t objSize = current_obj.size();
+		for (size_t i = 0; i < objSize; ++i) {
+			// 双重索引验证
+			if (i >= objSize || i >= current_obj.size()) {
+				std::cerr << "Index " << i << " out of range (size: "
+					<< current_obj.size() << ")" << std::endl;
 				return false;
 			}
 
-			pt.add_child(obj.GetKey(i), subpt);
-			//std::cout << "[ParseDataObjectToPt] Successfully added nested object with key: "
-				//<< obj.GetKey(i) << std::endl;
-		}
-		else
-		{
-			const char* value = static_cast<const char*>(obj[i]); // 明确类型转换
-			if (!value) { // 处理空指针(使用空字符串替代)
-				pt.add(key, "");
-			}
-			else {
-				// 4. 检查字符串终止符(防止越界读取)
-				size_t strLen = 0;
-				while (strLen < 1024 * 1024 && value[strLen] != '\0') { // 限制最大长度
-					strLen++;
+			try {
+				const char* key = current_obj.GetKey(i);
+				if (!key || *key == '\0') {
+					std::cerr << "Depth " << depth << ": Invalid key at index " << i
+						<< " (size: " << current_obj.size() << ")" << std::endl;
+
+					// 跳过无效键而不是中止整个解析
+					continue;
 				}
-				if (strLen >= 1024 * 1024) { // 超长字符串可能是无效数据
-					std::cerr << "Value too long (key=" << key << ")" << std::endl;
-					return false;
+
+				ResDataObject& child = current_obj[i];
+
+				// 更健壮的类型检查
+				if (child.IsObject() && child.size() > 0) {
+					ptree subpt;
+					if (!self(self, subpt, child, depth + 1)) {
+						std::cerr << "Depth " << depth << ": Failed parsing nested object '"
+							<< key << "' (size: " << child.size() << ")" << std::endl;
+						return false;
+					}
+					current_pt.add_child(key, subpt);
 				}
-				pt.add(key, value);
+				else {
+					try {
+						// 安全的类型转换
+						const char* value = static_cast<const char*>(child);
+						current_pt.put(key, value ? value : "");
+					}
+					catch (...) {
+						current_pt.put(key, "");
+					}
+				}
+			}
+			catch (const ResDataObjectExption& e) {
+				std::cerr << "Depth " << depth << ": Exception at index " << i
+					<< ": " << e.what() << std::endl;
+				return false;
+			}
+			catch (const std::exception& e) {
+				std::cerr << "Depth " << depth << ": Std exception at index " << i
+					<< ": " << e.what() << std::endl;
+				return false;
+			}
+			catch (...) {
+				std::cerr << "Depth " << depth << ": Unknown exception at index " << i << std::endl;
+				return false;
 			}
 		}
-	}
+		return true;
+		};
 
-	//std::cout << "[ParseDataObjectToPt] Exiting function successfully" << std::endl;
-	return true;
+	// 初始调用添加保护
+	try {
+		return recursive_parse(recursive_parse, pt, obj, 0);
+	}
+	catch (...) {
+		std::cerr << "Top-level exception in ParseDataObjectToPt" << std::endl;
+		return false;
+	}
 }
 
 ResDataObjectExption::ResDataObjectExption(const char *pExp) : m_ExpContext(std::make_unique<std::string>(pExp ? pExp : "")) {}
@@ -288,7 +308,7 @@ ResDataObjectExption::ResDataObjectExption(const ResDataObjectExption &tValue) :
 
 ResDataObjectExption::~ResDataObjectExption(void) = default;
 
-const char *ResDataObjectExption::what()
+const char *ResDataObjectExption::what() const
 {
 	if(m_ExpContext->size() == 0)
 	{
@@ -326,6 +346,23 @@ ResDataObject_Pair& ResDataObject_Pair::operator=(const ResDataObject_Pair& othe
 	return *this;
 }
 
+ResDataObject_Pair& ResDataObject_Pair::operator=(ResDataObject_Pair&& other) noexcept
+{
+	if (this != &other) {
+		first = std::move(other.first);
+		second = std::move(other.second);
+
+		// 确保源对象处于有效状态(与移动构造逻辑一致)
+		if (!other.first) {
+			other.first = std::make_unique<std::string>();
+		}
+		if (!other.second) {
+			other.second = std::make_unique<ResDataObject>();
+		}
+	}
+	return *this;
+}
+
 ResDataObject::ResDataObject(void) : 
 	m_encode(std::make_unique<std::string>()),
 m_value(std::make_unique<std::string>()),
@@ -336,11 +373,12 @@ ResDataObject::ResDataObject(const ResDataObject& tValue)
 	m_value(std::make_unique<std::string>(*tValue.m_value)),
 	m_vec(std::make_unique<std::vector<ResDataObject_Pair>>()) 
 {
-
 	m_vec->reserve(tValue.m_vec->size());
 	for (const auto& pair : *tValue.m_vec) {
 		m_vec->push_back(pair);
 	}
+	//std::cerr << "[ResDataObject] Copied to " << this
+		//<< ", m_vec=" << m_vec.get() << std::endl;
 }
 
 ResDataObject::ResDataObject(ResDataObject&& tValue) noexcept
@@ -351,6 +389,12 @@ ResDataObject::ResDataObject(ResDataObject&& tValue) noexcept
 	tValue.m_encode = std::make_unique<std::string>();
 	tValue.m_value = std::make_unique<std::string>();
 	tValue.m_vec = std::make_unique<std::vector<ResDataObject_Pair>>();
+	//std::cerr << "[ResDataObject] move to " << this
+		//<< ", m_vec=" << m_vec.get() << std::endl;
+}
+
+ResDataObject::~ResDataObject(void)
+{
 }
 
 ResDataObject& ResDataObject::operator=(ResDataObject&& tValue) noexcept {
@@ -359,6 +403,10 @@ ResDataObject& ResDataObject::operator=(ResDataObject&& tValue) noexcept {
 		m_value = std::move(tValue.m_value);
 		m_vec = std::move(tValue.m_vec);
 	}
+
+	if (!tValue.m_vec) {
+		tValue.m_vec = std::make_unique<std::vector<ResDataObject_Pair>>();
+	}
 	return *this;
 }
 
@@ -371,12 +419,8 @@ void ResDataObject::clear()
 	m_vec->clear();
 }
 
-size_t ResDataObject::size() 
-{
-	if (m_vec) {
-		return m_vec->size();
-	}
-	return 0; // m_vec为空时返回0
+size_t ResDataObject::size() {
+	return m_vec->size();
 }
 
 bool ResDataObject::IsObject()
@@ -389,8 +433,8 @@ const char *ResDataObject::encode()
 	if (m_vec->empty() && !m_value->empty()) {
 		return m_value->c_str();
 	}
-	ptree pt;  
 
+	boost::property_tree::ptree pt;
 	if(ParseDataObjectToPt(pt,(*this)) == true)
 	{
 		std::stringstream strm;
@@ -400,8 +444,6 @@ const char *ResDataObject::encode()
 	}
 
 	throw ResDataObjectExption("encode failed. ");
-
-	return NULL;
 }
 
 bool ResDataObject::decode( const char *pdata )
@@ -671,8 +713,12 @@ void ResDataObject::MakeKeyLower()
 ResDataObject& ResDataObject::operator = (const char* pVal)
 {
 	clear();
-
-	(*m_value) = (pVal);
+	if (!pVal || reinterpret_cast<uintptr_t>(pVal) < 0x1000) {  // 0x1000是常见的用户态有效内存起始阈值
+		*m_value = "";  // 用空字符串替代无效指针
+	}
+	else {
+		*m_value = pVal;  // 仅在指针有效时赋值
+	}
 	return (*this);
 };
 
@@ -696,7 +742,6 @@ ResDataObject &ResDataObject::operator [](int idx)
 	if(idx < 0)
 	{
 		throw ResDataObjectExption("using minus idx to operate []");
-		return (*this);
 	}
 
 	size_t idx_local = (size_t)idx;
@@ -742,7 +787,6 @@ const char* ResDataObject::GetKey(int idx)
 	if(idx < 0)
 	{
 		throw ResDataObjectExption("try to get key with minus idx");
-		return (*this);
 	}
 
 	size_t idx_local = (size_t)idx;
@@ -994,7 +1038,11 @@ ResDataObject::operator double()
 
 ResDataObject::operator const char*()
 {
-	return m_value->c_str();
+	if (!m_value) {
+		std::cerr << "[ResDataObject] operator const char*: m_value is null" << std::endl;
+		return "";  // 返回空字符串避免崩溃
+	}
+	return (*m_value).c_str();
 };
 
 
@@ -1084,10 +1132,9 @@ int ResDataObject::GetNextOf(const char *pKey,int PrevIdx)
 //erase
 bool ResDataObject::eraseAllOf(const char *pKey)
 {
-	if(pKey == NULL)
-	{
-		clear();
-		return true;
+	if (pKey == NULL) {
+		throw ResDataObjectExption("eraseAllOf: pKey cannot be NULL");
+		return false;
 	}
 	std::string keyname = (pKey);
 	//keyname = CCommonFun::MAKELOWER(keyname);
@@ -1313,7 +1360,7 @@ ResDataObject& ResDataObject::operator = (const double tValue)
 
 	//新方案(丢精度)
 	char szStr[64];
-	snprintf(szStr, sizeof(szStr), "%.6f", tValue);
+	snprintf(szStr, sizeof(szStr), "%.17g", tValue); 
 
 	strm << szStr;
 	(*this) = strm.str().c_str();
@@ -1429,27 +1476,39 @@ bool ResDataObject::add(const char* pKey,double tValue)
 bool ResDataObject::add(const char* pKey,const char* pValue)
 {
 	ResDataObject obj;
-	obj = pValue;
+	if (!pValue || reinterpret_cast<uintptr_t>(pValue) < 0x1000) {
+		obj = "";  // 无效值用空字符串替代
+	}
+	else {
+		obj = pValue;
+	}
 	return add(pKey,obj);
 }
 
-
 bool ResDataObject::add(const char* pKey,ResDataObject &dataobj)
 {
+	if (!m_vec) {
+		std::cerr << "Error: m_vec is null in ResDataObject::add" << std::endl;
+		m_vec = std::make_unique<std::vector<ResDataObject_Pair>>();  
+	}
+
 	if (!pKey) pKey = ""; // 处理空指针
 
-	ResDataObject_Pair new_pair;
-	*new_pair.first = pKey; // 安全赋值
 
-	// 深拷贝dataobj
-	*new_pair.second = dataobj;
+	try {
 
-	m_vec->push_back(std::move(new_pair));
-	return true;
+		m_vec->emplace_back();
+		auto& new_pair = m_vec->back();
+		*new_pair.first = pKey;
+		*new_pair.second = dataobj;
+		return true;
+	}
+	catch (...) {
+		std::cerr << "[add] vector@" << m_vec.get() << " is invalid (memory corrupted)" << std::endl;
+		return false;
+	}
 };
 
-
-
 bool ResDataObject::update(const char* pKey,bool tValue)
 {
 	eraseAllOf(pKey);

+ 12 - 20
ResDataObject/ResDataObject.h

@@ -49,7 +49,7 @@ public:
 	ResDataObjectExption(const char *pExp);
 	~ResDataObjectExption(void);
 	ResDataObjectExption& operator = (const ResDataObjectExption &tValue);
-	const char *what();
+	const char* what() const;
 
 };
 
@@ -158,31 +158,23 @@ public:
 	ResDataObject_Pair();
 	~ResDataObject_Pair() = default;
 	ResDataObject_Pair(const ResDataObject_Pair& other);
-	ResDataObject_Pair& operator=(const ResDataObject_Pair& other);
 	// 添加移动构造函数
 	ResDataObject_Pair(ResDataObject_Pair&& other) noexcept
 		: first(std::move(other.first))
 		, second(std::move(other.second))
 	{
-	}
-
-	// 添加移动赋值运算符
-	ResDataObject_Pair& operator=(ResDataObject_Pair&& other) noexcept
-	{
-		if (this != &other) {
-			first = std::move(other.first);
-			second = std::move(other.second);
-
-			// 确保源对象处于有效状态
-			if (!other.first) {
-				other.first = std::make_unique<std::string>();
-			}
-			if (!other.second) {
-				other.second = std::make_unique<ResDataObject>();
-			}
+		// 移动后重置源对象,确保其成员非空
+		if (!other.first) {
+			other.first = std::make_unique<std::string>();
+		}
+		if (!other.second) {
+			other.second = std::make_unique<ResDataObject>();
 		}
-		return *this;
 	}
+
+	ResDataObject_Pair& operator=(const ResDataObject_Pair& other);
+	ResDataObject_Pair& operator=(ResDataObject_Pair&& other) noexcept;
+	
 };
 
 class RESDATAOBJECT_API ResDataObject
@@ -199,7 +191,7 @@ public:
 	ResDataObject(void);
 	ResDataObject(const ResDataObject &tValue);
 	ResDataObject(ResDataObject&& tValue) noexcept;
-	~ResDataObject(void) = default;
+	~ResDataObject(void);
 
 	ResDataObject& operator=(ResDataObject&& tValue) noexcept;