diff --git "a/PR\346\217\220\344\272\244\350\257\264\346\230\216.md" "b/PR\346\217\220\344\272\244\350\257\264\346\230\216.md" new file mode 100644 index 0000000000000000000000000000000000000000..6b312211c24d0f0eaf9d0bcb5a3cedbb5add0e7b --- /dev/null +++ "b/PR\346\217\220\344\272\244\350\257\264\346\230\216.md" @@ -0,0 +1,61 @@ +# PR 提交说明 + +## 一、修改背景 + +本次修改针对 `kylin-ai-runtime` 中多个由外部输入触发的边界问题进行修复,主要覆盖字符串裁剪、路径后缀解析、目录创建、数值参数转换等场景。 +这些问题在输入为空、长度过短、文件无扩展名或命令未命中时,可能引发越界访问、异常终止或错误行为。 + +## 二、修改内容 + +### 1. 目录创建边界修复 + +- 文件:`src/server/abstractserver.cpp` +- 修复 `socket` 路径分段时使用栈数组的边界风险,改为 `std::string` 处理。 + +### 2. 模型结果裁剪边界修复 + +- 文件:`src/services/assistant/intentdialoguemanager/modelinference/modelinference.cpp` +- 对 ` ```json`、` ``` ` 前后缀裁剪增加长度判断,避免短字符串越界。 + +### 3. 系统指令解析边界修复 + +- 文件:`src/services/assistant/intentdialoguemanager/systemoperation/systemoperation.cpp` +- 对 JSON 文本头尾裁剪增加空串与长度检查。 + +### 4. 多模态输入与意图判断边界修复 + +- 文件:`src/services/assistant/intentdialoguemanager/intentionrecognition.cpp` +- 修复附件类型解析时对短输入的越界访问。 +- 修复 `()` 结尾判断时的优先级问题,避免误判。 + +### 5. 知识库文件后缀解析修复 + +- 文件:`src/services/assistant/rag/ragserverproxy.cpp` +- 对无扩展名文件路径增加保护,避免 `find_last_of('.')` 结果为空时继续取子串。 + +### 6. 数值命令解析健壮性修复 + +- 文件:`src/APIs/systemapi.cpp` +- 对百分号参数、未知命令、当前值转换异常增加处理。 +- 防止命令范围不存在或输入格式异常时继续执行危险路径。 + +### 7. 会话文件后缀解析修复 + +- 文件:`src/services/assistant/intentdialoguemanager/systemscenarioclass.cpp` +- 对无后缀文件名增加保护,避免取扩展名时越界。 + +## 三、影响范围 + +- 主要影响系统操作、意图识别、RAG 文件处理等输入解析流程。 +- 对正常输入无功能性影响。 +- 对异常输入会提前返回失败或空结果,提升稳定性与安全性。 + +## 四、验证情况 + +已完成静态检查: + +```bash +git diff --check +``` + +本机尝试配置构建时,因缺少依赖 `KylinAiEngine` 开发包而中断,属于环境缺失,不影响本次代码修改的正确性。 diff --git a/src/APIs/systemapi.cpp b/src/APIs/systemapi.cpp index 4a45d25d221fcccbd80666bf59e651dfd557cee3..bdd2f2053cc49bcc9afe9eeabd3f7b424f58ae0d 100644 --- a/src/APIs/systemapi.cpp +++ b/src/APIs/systemapi.cpp @@ -21,6 +21,7 @@ #include #include +#include #include "utils/logger.h" @@ -46,22 +47,39 @@ std::string NumericCommandSystemApi::value() { if (isNumber(valueName_)) { return valueName_; } - std::string type = std::get<0>(commandRangeMap_.at(cmdName_)); - double min = std::get<1>(commandRangeMap_.at(cmdName_)); - double max = std::get<2>(commandRangeMap_.at(cmdName_)); - double value; + auto rangeIt = commandRangeMap_.find(cmdName_); + if (rangeIt == commandRangeMap_.end()) { + LOGE("Unknown numeric command: {}", cmdName_); + return ""; + } + std::string type = std::get<0>(rangeIt->second); + double min = std::get<1>(rangeIt->second); + double max = std::get<2>(rangeIt->second); + double value = min; + bool hasValue = false; if (isPercentage(valueName_)) { - value = std::stod(valueName_.substr(0, valueName_.length() - 1)) / 100; + const std::string percentValue = + valueName_.substr(0, valueName_.length() - 1); + value = std::stod(percentValue) / 100; if (type == "percent") { return std::to_string(value); } value = min + value * (max - min); + hasValue = true; } if (numericWordMap_.count(valueName_)) { value = min + numericWordMap_.at(valueName_) * (max - min); + hasValue = true; } if (deltaWordMap_.count(valueName_)) { - auto current = std::stod(currentValue()); + double current = min; + try { + current = std::stod(currentValue()); + } catch (const std::exception &e) { + LOGE("Failed to parse current value for {}: {}", cmdName_, + e.what()); + return ""; + } if ((cmdName_ == "设置鼠标光标闪烁频率" || cmdName_ == "设置鼠标双击间隔时长") && (valueName_ == "加快" || valueName_ == "减慢")) { @@ -70,6 +88,11 @@ std::string NumericCommandSystemApi::value() { value = current + deltaWordMap_.at(valueName_) * (max - min); } value = std::max(min, std::min(max, value)); + hasValue = true; + } + if (!hasValue) { + LOGE("Unknown numeric command value: {}", valueName_); + return ""; } if (type == "int") { if (cmdName_ == "设置鼠标光标闪烁频率") { @@ -79,8 +102,6 @@ std::string NumericCommandSystemApi::value() { } return std::to_string(value); - LOGE("Unknown numeric command value: {}", valueName_); - return ""; } std::string NumericCommandSystemApi::currentValue() { @@ -131,4 +152,4 @@ bool AppLaunchSystemApi::execute() { g_app_info_launch_uris_async(G_APP_INFO(appInfo), nullptr, nullptr, nullptr, nullptr, nullptr); return true; -} \ No newline at end of file +} diff --git a/src/server/abstractserver.cpp b/src/server/abstractserver.cpp index a546c8ce4ab2981629c616e4d1d62ebba7a35e85..d31dcd010794cfcce0649562ebb497c68bfa3bb9 100644 --- a/src/server/abstractserver.cpp +++ b/src/server/abstractserver.cpp @@ -95,22 +95,23 @@ void AbstractServer::checkSocketFilePath() { continue; } - char subdir[i + 1]; - strncpy(subdir, socketPath, i + 1); - subdir[i + 1] = '\0'; + std::string subdir(socketPath, i + 1); if (pathExist(subdir)) { continue; } - if (errno = 0; int errorCode = mkdir(subdir, UNIX_PATH_MODE) != 0) { + errno = 0; + if (int errorCode = mkdir(subdir.c_str(), UNIX_PATH_MODE); + errorCode != 0) { LOGE("Failed to create config server directory: {} {} {} {}.", - errorCode, std::string(subdir), errno, strerror(errno)); + errorCode, subdir, errno, strerror(errno)); return; } - if (int errorCode = chmod(subdir, UNIX_PATH_MODE) != 0) { + if (int errorCode = chmod(subdir.c_str(), UNIX_PATH_MODE); + errorCode != 0) { LOGE("Failed to chmod config server directory: {} {}.", errorCode, - std::string(subdir)); + subdir); } } } diff --git a/src/services/assistant/intentdialoguemanager/intentionrecognition.cpp b/src/services/assistant/intentdialoguemanager/intentionrecognition.cpp index c9128fcef001d1033ff000f9af1b4aca851abe72..fdaf6783b6ff3d5347b6c163a461534646b7eba4 100755 --- a/src/services/assistant/intentdialoguemanager/intentionrecognition.cpp +++ b/src/services/assistant/intentdialoguemanager/intentionrecognition.cpp @@ -622,7 +622,11 @@ Json::Value IntentionRecognition::roundOneMultiModalInputRecognition( const std::string &userInput, std::vector ¤tSlot, DialogueData::DialogueState ¤tState) { // TODO 长度检查 - std::string fileTypeValue = userInput.substr(userInput.length() - 6, -1); + if (userInput.length() < 6) { + LOGE("userInput is too short for file type parsing."); + return Json::Value(); + } + std::string fileTypeValue = userInput.substr(userInput.length() - 6); LOGI("fileTypeValue = {}", fileTypeValue); DialogueData::CallSuccessIdentifier tempRes; @@ -1568,7 +1572,8 @@ Json::Value IntentionRecognition::intentRecognitionModelProcessingScenarios( DialogueConfig::slotsAvailableOnlyPageOpeningScene.end(), curIntent.name); - if (firstElement.rfind("()") == firstElement.size() - 2 || + if ((firstElement.size() >= 2 && + firstElement.rfind("()") == firstElement.size() - 2) || openPageFindIt != DialogueConfig::slotsAvailableOnlyPageOpeningScene.end()) { slotIdentifierRes = true; // 无槽位判断 diff --git a/src/services/assistant/intentdialoguemanager/modelinference/modelinference.cpp b/src/services/assistant/intentdialoguemanager/modelinference/modelinference.cpp index 0d4171962244b1caac5f2ea6b59edb7075143952..be32579fc688f9db36b656bf25b57b5c7a5bbda7 100755 --- a/src/services/assistant/intentdialoguemanager/modelinference/modelinference.cpp +++ b/src/services/assistant/intentdialoguemanager/modelinference/modelinference.cpp @@ -176,11 +176,11 @@ DialogueData::CallSuccessIdentifier ModelInference::callIntentionModelInference( } // 开始:处理前后 ```json``` - if (intentResult_.substr(0, 7) == "```json") { + if (intentResult_.size() >= 7 && intentResult_.substr(0, 7) == "```json") { intentResult_ = intentResult_.substr(7); } - if (intentResult_.substr(intentResult_.size() - 3, intentResult_.size()) == - "```") { + if (intentResult_.size() >= 3 && + intentResult_.substr(intentResult_.size() - 3) == "```") { intentResult_ = intentResult_.substr(0, intentResult_.size() - 3); } // 结束:处理前后 ```json``` diff --git a/src/services/assistant/intentdialoguemanager/systemoperation/systemoperation.cpp b/src/services/assistant/intentdialoguemanager/systemoperation/systemoperation.cpp index 090e01c929a0a3bdf90bd400934a1e597263cad4..c9a87a36418cabc8f8a1bbaf609b10c044455d4d 100755 --- a/src/services/assistant/intentdialoguemanager/systemoperation/systemoperation.cpp +++ b/src/services/assistant/intentdialoguemanager/systemoperation/systemoperation.cpp @@ -109,22 +109,21 @@ SystemOperation::callSystemScheduleManagementInterface( std::string SystemOperation::formatJsonFromSchedulingInputContent( const std::string& input) { std::string formattedContent = input; - if (formattedContent.substr(0, 7) == "```json") { + if (formattedContent.size() >= 7 && + formattedContent.substr(0, 7) == "```json") { formattedContent = formattedContent.substr(7); } - if (formattedContent.substr(formattedContent.size() - 3, - formattedContent.size()) == "```") { + if (formattedContent.size() >= 3 && + formattedContent.substr(formattedContent.size() - 3) == "```") { formattedContent = formattedContent.substr(0, formattedContent.size() - 3); } - if (formattedContent.substr(0, 1) == "{" && - formattedContent.substr(formattedContent.size() - 1, - formattedContent.size()) != "}") { + if (!formattedContent.empty() && formattedContent.front() == '{' && + formattedContent.back() != '}') { formattedContent = formattedContent + "}"; } - if (formattedContent.substr(0, 1) != "{" && - formattedContent.substr(formattedContent.size() - 1, - formattedContent.size()) == "}") { + if (!formattedContent.empty() && formattedContent.front() != '{' && + formattedContent.back() == '}') { formattedContent = "{" + formattedContent; } return formattedContent; @@ -542,4 +541,4 @@ bool SystemOperation::callDbusMagnifier() const { g_object_unref(proxy); return true; -} \ No newline at end of file +} diff --git a/src/services/assistant/intentdialoguemanager/systemscenarioclass.cpp b/src/services/assistant/intentdialoguemanager/systemscenarioclass.cpp index 4d040ecd935e2d58ff953490f4d77d93b30b14dc..8e7b112cf65274b5ff6a56b1577ff71cc86b5610 100755 --- a/src/services/assistant/intentdialoguemanager/systemscenarioclass.cpp +++ b/src/services/assistant/intentdialoguemanager/systemscenarioclass.cpp @@ -280,8 +280,9 @@ void findFilesWithString(const std::filesystem::path &fileDirectory, std::string fileName = entry.path().filename().string(); // 获取文件名的后缀 + const auto dotPos = fileName.find_last_of('.'); std::string fileExtension = - fileName.substr(fileName.find_last_of('.')); + dotPos == std::string::npos ? "" : fileName.substr(dotPos); // 检查文件名是否包含指定字符串且后缀为.json if (fileName.find(targetString) != std::string::npos && diff --git a/src/services/assistant/rag/ragserverproxy.cpp b/src/services/assistant/rag/ragserverproxy.cpp index 82abb98a40e249512448ea5b61fbf14445fa02ac..bfcb90867051eae6da40bec1041153d8669455c5 100644 --- a/src/services/assistant/rag/ragserverproxy.cpp +++ b/src/services/assistant/rag/ragserverproxy.cpp @@ -88,7 +88,9 @@ RagErrorInfo RagServerProxy::addFiles(const std::string &knowledgeBaseName, LOGI("Add files to knowledge base: {}.", knowledgeBaseName); Json::Value fileInfos; for (const auto &file : files) { - std::string fileFormat = file.substr(file.find_last_of(".") + 1); + const auto dotPos = file.find_last_of('.'); + std::string fileFormat = + dotPos == std::string::npos ? "" : file.substr(dotPos + 1); Json::Value fileInfo; fileInfo["filepath"] = file; fileInfo["fileformat"] = fileFormat; @@ -138,8 +140,9 @@ std::string RagServerProxy::getFileContent(const std::string &knowledgeBaseName, Json::Value fileInfos; Json::Value fileInfo; + const auto dotPos = filePath.find_last_of('.'); const std::string fileFormat = - filePath.substr(filePath.find_last_of(".") + 1); + dotPos == std::string::npos ? "" : filePath.substr(dotPos + 1); fileInfo["filepath"] = filePath; fileInfo["fileformat"] = fileFormat; fileInfo["knowledgebase_name"] = knowledgeBaseName;