| @@ -91,8 +91,42 @@ STATIC TraStatus TraceMkdirRecur(const char *dirPath) | |||||||||||||||
| 91 | return err; | 91 | return err; | ||||||||||||
| 92 | } | 92 | } | ||||||||||||
| 93 | 93 | ||||||||||||||
| 94 | +STATIC TraStatus TraceNormalizeEnvPath(char *envDir, uint32_t len) | ||||||||||||||
级别:一般
问题:未对空字符串场景做处理。当 envDir 为 "" 时,envDir[0] != '/',会进入归一化分支,生成 " ![]() ![]() | |||||||||||||||
| 95 | +{ | ||||||||||||||
| 96 | + if ((envDir == NULL) || (len == 0U) || (envDir[0] == '\0')) { | ||||||||||||||
| 97 | + ADIAG_WAR("ASCEND_WORK_PATH is invalid."); | ||||||||||||||
| 98 | + return TRACE_FAILURE; | ||||||||||||||
| 99 | + } | ||||||||||||||
| 100 | + if (envDir[0] == '/') { | ||||||||||||||
| 101 | + return TRACE_SUCCESS; | ||||||||||||||
| 102 | + } | ||||||||||||||
| 103 | + | ||||||||||||||
| 104 | + char cwd[MAX_FILEDIR_LEN + 1U] = { 0 }; | ||||||||||||||
| 105 | + if (getcwd(cwd, sizeof(cwd)) == NULL) { | ||||||||||||||
| 106 | + ADIAG_WAR("get current directory failed, strerr=%s.", strerror(AdiagGetErrorCode())); | ||||||||||||||
| 107 | + return TRACE_FAILURE; | ||||||||||||||
级别:提示 问题:absPath 与 cwd 缓冲固定为 MAX_FILEDIR_LEN+1,但 envDir 的容量由参数 len 决定。当 cwd 与 envDir 拼接后长度超过 MAX_FILEDIR_LEN 时,snprintf_s 截断后返回 -1,函数返回失败,行为可接受但缺少对路径过长的明确日志区分。 影响:路径过长导致的失败与环境/系统调用失败混在一起,排障困难。 修复建议:可在 snprintf_s 失败时进一步使用 strerror(errno) 或单独日志标注是路径过长,便于定位。 ![]() ![]() | |||||||||||||||
| 108 | + } | ||||||||||||||
| 109 | + | ||||||||||||||
| 110 | + char absPath[MAX_FILEDIR_LEN + 1U] = { 0 }; | ||||||||||||||
| 111 | + int32_t ret = snprintf_s(absPath, sizeof(absPath), sizeof(absPath) - 1U, "%s/%s", cwd, envDir); | ||||||||||||||
| 112 | + if (ret == -1) { | ||||||||||||||
| 113 | + ADIAG_WAR("build ASCEND_WORK_PATH absolute path failed, path may exceed %u bytes, cwd=%s, env=%s.", | ||||||||||||||
| 114 | + MAX_FILEDIR_LEN, cwd, envDir); | ||||||||||||||
| 115 | + return TRACE_FAILURE; | ||||||||||||||
级别:一般 问题:若 envDir 由 getenv() 返回的指针直接传入,TraceNormalizeEnvPath 使用 strcpy_s 原地改写 envDir 内容,属于修改 getenv 返回值,POSIX 标准中该行为未定义。 影响:若上游确实传入 getenv() 返回的内存,可能破坏进程环境块、引发 UB 或在多线程读取环境变量时出现数据竞争。 修复建议:确认调用链中 envDir 是否为 getenv 直接返回值;若是,应改为拷贝到本地缓冲后再归一化,避免修改 getenv 返回值。 ![]() ![]() | |||||||||||||||
| 116 | + } | ||||||||||||||
| 117 | + ret = strcpy_s(envDir, len, absPath); | ||||||||||||||
🟡 Medium Priority 在 触发条件: 失败后果: 建议:将 改动建议
![]() ![]() 不准确? | |||||||||||||||
| 118 | + if (ret != EOK) { | ||||||||||||||
| 119 | + ADIAG_WAR("copy ASCEND_WORK_PATH absolute path failed, ret=%d.", ret); | ||||||||||||||
| 120 | + return TRACE_FAILURE; | ||||||||||||||
| 121 | + } | ||||||||||||||
| 122 | + return TRACE_SUCCESS; | ||||||||||||||
| 123 | +} | ||||||||||||||
| 124 | + | ||||||||||||||
| 94 | STATIC TraStatus TraceGetValidPath(char *envDir, uint32_t len) | 125 | STATIC TraStatus TraceGetValidPath(char *envDir, uint32_t len) | ||||||||||||
| 95 | { | 126 | { | ||||||||||||
| 127 | + if (TraceNormalizeEnvPath(envDir, len) != TRACE_SUCCESS) { | ||||||||||||||
| 128 | + return TRACE_FAILURE; | ||||||||||||||
| 129 | + } | ||||||||||||||
| 96 | if ((TraceAccess(envDir, F_OK) != EN_OK) && (TraceMkdirRecur(envDir) != EN_OK)) { | 130 | if ((TraceAccess(envDir, F_OK) != EN_OK) && (TraceMkdirRecur(envDir) != EN_OK)) { | ||||||||||||
| 97 | ADIAG_WAR("path %s doesn't exist.", envDir); | 131 | ADIAG_WAR("path %s doesn't exist.", envDir); | ||||||||||||
| 98 | return TRACE_FAILURE; | 132 | return TRACE_FAILURE; | ||||||||||||
| @@ -182,16 +216,16 @@ STATIC TraStatus TraceInitRootPath(TraceRecorderMgr *mgr) | |||||||||||||||
| 182 | return TRACE_FAILURE; | 216 | return TRACE_FAILURE; | ||||||||||||
| 183 | } | 217 | } | ||||||||||||
| 184 | 218 | ||||||||||||||
| 185 | - char *path = (char *)AdiagMalloc(MAX_FILEDIR_LEN); | 219 | + char *path = (char *)AdiagMalloc(MAX_FILEDIR_LEN + 1U); | ||||||||||||
| 186 | ADIAG_CHK_EXPR_ACTION(path == NULL, return TRACE_FAILURE, | 220 | ADIAG_CHK_EXPR_ACTION(path == NULL, return TRACE_FAILURE, | ||||||||||||
| 187 | "malloc root path failed, strerr=%s", strerror(AdiagGetErrorCode())); | 221 | "malloc root path failed, strerr=%s", strerror(AdiagGetErrorCode())); | ||||||||||||
| 188 | 222 | ||||||||||||||
| 189 | - TraStatus ret = TraceGetEnvPath(path, MAX_FILEDIR_LEN); | 223 | + TraStatus ret = TraceGetEnvPath(path, MAX_FILEDIR_LEN + 1U); | ||||||||||||
| 190 | if (ret == TRACE_SUCCESS) { | 224 | if (ret == TRACE_SUCCESS) { | ||||||||||||
| 191 | res = snprintf_truncated_s(mgr->rootPath, MAX_FILEDIR_LEN + 1U, "%s", path); | 225 | res = snprintf_truncated_s(mgr->rootPath, MAX_FILEDIR_LEN + 1U, "%s", path); | ||||||||||||
| 192 | } else { | 226 | } else { | ||||||||||||
| 193 | // get process user home path | 227 | // get process user home path | ||||||||||||
| 194 | - ret = TraceGetHomeDir(path, MAX_FILEDIR_LEN); | 228 | + ret = TraceGetHomeDir(path, MAX_FILEDIR_LEN + 1U); | ||||||||||||
| 195 | if (ret != TRACE_SUCCESS) { | 229 | if (ret != TRACE_SUCCESS) { | ||||||||||||
| 196 | ADIAG_SAFE_FREE(path); | 230 | ADIAG_SAFE_FREE(path); | ||||||||||||
| 197 | ADIAG_ERR("get home directory failed, ret=%d.", ret); | 231 | ADIAG_ERR("get home directory failed, ret=%d.", ret); | ||||||||||||
| @@ -20,7 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | 22 | ||
| 23 | + | ||
| 23 | 24 | ||
| 25 | + | ||
| 24 | 26 | ||
| 25 | 27 | ||
| 26 | 28 | ||
| @@ -28,6 +30,7 @@ static std::atomic<uint32_t> g_traceOpenCallIndex(0); | |||
| 28 | static std::atomic<bool> g_firstTraceOpenEntered(false); | 30 | static std::atomic<bool> g_firstTraceOpenEntered(false); |
| 29 | static std::atomic<bool> g_allowFirstTraceOpen(false); | 31 | static std::atomic<bool> g_allowFirstTraceOpen(false); |
| 30 | static std::atomic<bool> g_agingThreadDone(false); | 32 | static std::atomic<bool> g_agingThreadDone(false); |
| 33 | +static std::atomic<uint32_t> g_strcpyCallIndex(0); | ||
| 31 | 34 | ||
| 32 | typedef struct { | 35 | typedef struct { |
| 33 | TraceDirInfo dirInfo; | 36 | TraceDirInfo dirInfo; |
| @@ -59,6 +62,39 @@ int32_t TraceOpenBlockFirstThenOpen(const char *filePath, int32_t flag, uint32_t | |||
| 59 | return fd; | 62 | return fd; |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 65 | +TraStatus TraceHandleEmptyEnvStringStub(const char *env, char *buf, uint32_t len) | ||
| 66 | +{ | ||
| 67 | + (void)env; | ||
| 68 | + if ((buf == nullptr) || (len == 0U)) { | ||
| 69 | + return TRACE_FAILURE; | ||
| 70 | + } | ||
| 71 | + buf[0] = '\0'; | ||
| 72 | + return TRACE_SUCCESS; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +TraStatus TraceHandleRelativeEnvStringStub(const char *env, char *buf, uint32_t len) | ||
| 76 | +{ | ||
| 77 | + (void)env; | ||
| 78 | + const char relativePath[] = "trace_recorder_copy_failed_path"; | ||
| 79 | + if ((buf == nullptr) || (len <= strlen(relativePath))) { | ||
| 80 | + return TRACE_FAILURE; | ||
| 81 | + } | ||
| 82 | + errno_t ret = memcpy_s(buf, len, relativePath, strlen(relativePath) + 1U); | ||
| 83 | + return (ret == EOK) ? TRACE_SUCCESS : TRACE_FAILURE; | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +errno_t StrcpyFailOnceThenCopy(char *strDest, size_t destMax, const char *strSrc) | ||
| 87 | +{ | ||
| 88 | + if (g_strcpyCallIndex.fetch_add(1U) == 0U) { | ||
| 89 | + return EINVAL; | ||
| 90 | + } | ||
| 91 | + if ((strDest == nullptr) || (strSrc == nullptr) || (destMax == 0U) || (strlen(strSrc) >= destMax)) { | ||
| 92 | + return EINVAL; | ||
| 93 | + } | ||
| 94 | + errno_t ret = memcpy_s(strDest, destMax, strSrc, strlen(strSrc) + 1U); | ||
| 95 | + return (ret == EOK) ? EOK : EINVAL; | ||
| 96 | +} | ||
| 97 | + | ||
| 62 | void *TraceRecorderGetFdThread(void *arg) | 98 | void *TraceRecorderGetFdThread(void *arg) |
| 63 | { | 99 | { |
| 64 | TraceGetFdThreadArg *threadArg = static_cast<TraceGetFdThreadArg *>(arg); | 100 | TraceGetFdThreadArg *threadArg = static_cast<TraceGetFdThreadArg *>(arg); |
| @@ -113,9 +149,52 @@ bool BuildRecorderFilePath(char *path, size_t len, const char *eventName, const | |||
| 113 | int32_t ret = snprintf_s(path, len, len - 1U, "%s/%s_tracer_%s%s", dirPath, tracerName, objName, suffix); | 149 | int32_t ret = snprintf_s(path, len, len - 1U, "%s/%s_tracer_%s%s", dirPath, tracerName, objName, suffix); |
| 114 | return ret != -1; | 150 | return ret != -1; |
| 115 | } | 151 | } |
| 116 | - | 152 | + |
级别:一般 问题:ScopedCwdAndEnv 通过 chdir 修改进程级 cwd,属于进程全局状态。若 gtest 启用并行执行(--jobs 或自定义 runner),或与 TestRecord_Concurrent 等用例并发运行,会相互污染工作目录。 影响:并行测试场景下用例间 cwd 相互干扰,出现间歇性失败、不稳定用例。 修复建议:在用例内禁用并行(或显式标注为串行用例);如必须改 cwd,考虑使用子进程隔离或在用例文档中明确依赖串行执行。 ![]() ![]() 级别:提示 问题:测试新增了相对路径场景,但缺少以下覆盖:1) envDir 为 NULL/空字符串的边界;2) 相对路径以 "./" 或 "../" 开头;3) cwd + envDir 拼接超过 MAX_FILEDIR_LEN 的截断/失败路径。 影响:新增逻辑的边界与异常分支未被覆盖,回归保护不足。 修复建议:补充对应 UT 用例,验证空字符串、"../"、超长路径等场景返回 TRACE_FAILURE。 ![]() ![]() | |||
| 117 | -class TraceRecorderUtest: public testing::Test { | 153 | +bool BuildRecorderFilePathWithRoot(char *path, size_t len, const char *rootPath, const char *eventName, |
| 118 | -protected: | 154 | + const char *dirTime, const char *tracerName, const char *objName, const char *suffix) |
| 155 | +{ | ||
| 156 | + int32_t ret = snprintf_s(path, len, len - 1U, "%s/atrace/trace_%d_%d_%s/%s_event_%d_%s/%s_tracer_%s%s", | ||
| 157 | + rootPath, TraceAttrGetPgid(), TraceAttrGetPid(), TraceAttrGetTime(), eventName, getpid(), dirTime, | ||
| 158 | + tracerName, objName, suffix); | ||
| 159 | + return ret != -1; | ||
| 160 | +} | ||
| 161 | + | ||
| 162 | +void RemoveTestPath(const std::string &path) | ||
| 163 | +{ | ||
| 164 | + if (path.empty()) { | ||
| 165 | + return; | ||
| 166 | + } | ||
| 167 | + std::string cmd = "rm -rf " + path; | ||
| 168 | + (void)system(cmd.c_str()); | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +class ScopedEnvAndPathCleanup { | ||
| 172 | +public: | ||
| 173 | + explicit ScopedEnvAndPathCleanup(const char *envName) : envName_(envName) | ||
| 174 | + { | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + ~ScopedEnvAndPathCleanup() | ||
| 178 | + { | ||
| 179 | + unsetenv(envName_); | ||
| 180 | + for (auto iter = cleanupPaths_.rbegin(); iter != cleanupPaths_.rend(); ++iter) { | ||
| 181 | + RemoveTestPath(*iter); | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + void AddPath(const std::string &path) | ||
| 186 | + { | ||
| 187 | + cleanupPaths_.push_back(path); | ||
| 188 | + RemoveTestPath(path); | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | +private: | ||
| 192 | + const char *envName_; | ||
| 193 | + std::vector<std::string> cleanupPaths_; | ||
| 194 | +}; | ||
| 195 | + | ||
| 196 | +class TraceRecorderUtest: public testing::Test { | ||
| 197 | +protected: | ||
| 119 | static void SetUpTestCase() | 198 | static void SetUpTestCase() |
| 120 | { | 199 | { |
| 121 | } | 200 | } |
| @@ -196,22 +275,164 @@ TEST_F(TraceRecorderUtest, TestRecord_Concurrent) | |||
| 196 | unsetenv("ASCEND_WORK_PATH"); | 275 | unsetenv("ASCEND_WORK_PATH"); |
| 197 | } | 276 | } |
| 198 | 277 | ||
| 199 | -TEST_F(TraceRecorderUtest, TestRecordEnvPath) | 278 | +TEST_F(TraceRecorderUtest, TestRecordEnvPath) |
| 200 | -{ | 279 | +{ |
| 201 | - TraceRecorderExit(); | 280 | + TraceRecorderExit(); |
| 202 | - setenv("ASCEND_WORK_PATH", LLT_TEST_DIR, 1); | 281 | + setenv("ASCEND_WORK_PATH", LLT_TEST_DIR, 1); |
| 203 | - EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | 282 | + EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit()); |
| 204 | 283 | ||
| 205 | TestRecorderWrite(1, 1, 2, TRACE_FILE_TXT_SUFFIX); | 284 | TestRecorderWrite(1, 1, 2, TRACE_FILE_TXT_SUFFIX); |
| 206 | - | 285 | + |
| 207 | - unsetenv("ASCEND_WORK_PATH"); | 286 | + unsetenv("ASCEND_WORK_PATH"); |
| 208 | -} | 287 | +} |
| 209 | - | 288 | + |
| 210 | -TEST_F(TraceRecorderUtest, TestRecordEnvInvalidPath) | 289 | +TEST_F(TraceRecorderUtest, TestRecordEnvRelativePath) |
| 211 | -{ | 290 | +{ |
| 212 | - printf("path doesn't exist, then create it successfully.\n"); | 291 | + TraceRecorderExit(); |
| 213 | - TraceRecorderExit(); | 292 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); |
| 214 | - setenv("ASCEND_WORK_PATH", LLT_TEST_DIR "/env/", 1); | 293 | + const std::string relativeDir = "trace_recorder_relative_path_ut"; |
| 294 | + envGuard.AddPath(relativeDir); | ||
| 295 | + setenv("ASCEND_WORK_PATH", ("./" + relativeDir).c_str(), 1); | ||
| 296 | + ASSERT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 297 | + | ||
| 298 | + const char *dirTime = "19700101080004000001"; | ||
| 299 | + TraceDirInfo dirInfo = { TRACER_SCHEDULE_NAME, getpid(), dirTime, true }; | ||
| 300 | + TraceFileInfo fileInfo = { TRACER_SCHEDULE_NAME, "relative", TRACE_FILE_TXT_SUFFIX }; | ||
| 301 | + int32_t fd = -1; | ||
| 302 | + auto ret = TraceRecorderGetFd(&dirInfo, &fileInfo, &fd); | ||
| 303 | + ASSERT_EQ(TRACE_SUCCESS, ret); | ||
| 304 | + EXPECT_EQ(TRACE_SUCCESS, TraceRecorderWrite(fd, "relative", 8U)); | ||
| 305 | + if (fd >= 0) { | ||
| 306 | + close(fd); | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + char cwd[MAX_FILEDIR_LEN + 1U] = {0}; | ||
| 310 | + ASSERT_NE(nullptr, getcwd(cwd, sizeof(cwd))); | ||
| 311 | + std::string expectedRoot = std::string(cwd) + "/" + relativeDir; | ||
| 312 | + char filePath[MAX_FULLPATH_LEN + 1U] = {0}; | ||
| 313 | + ASSERT_TRUE(BuildRecorderFilePathWithRoot(filePath, MAX_FULLPATH_LEN + 1U, expectedRoot.c_str(), | ||
| 314 | + TRACER_SCHEDULE_NAME, dirTime, TRACER_SCHEDULE_NAME, "relative", TRACE_FILE_TXT_SUFFIX)); | ||
| 315 | + EXPECT_EQ(0, access(filePath, F_OK)); | ||
| 316 | +} | ||
| 317 | + | ||
| 318 | +TEST_F(TraceRecorderUtest, TestRecordEnvRelativePathWithParentDir) | ||
| 319 | +{ | ||
| 320 | + TraceRecorderExit(); | ||
| 321 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 322 | + const std::string parentDir = "trace_recorder_relative_dotdot_parent"; | ||
| 323 | + const std::string targetDir = "trace_recorder_relative_dotdot_target"; | ||
| 324 | + envGuard.AddPath(parentDir); | ||
| 325 | + envGuard.AddPath(targetDir); | ||
| 326 | + setenv("ASCEND_WORK_PATH", (parentDir + "/../" + targetDir).c_str(), 1); | ||
| 327 | + ASSERT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 328 | + | ||
| 329 | + const char *dirTime = "19700101080004000002"; | ||
| 330 | + TraceDirInfo dirInfo = { TRACER_SCHEDULE_NAME, getpid(), dirTime, true }; | ||
| 331 | + TraceFileInfo fileInfo = { TRACER_SCHEDULE_NAME, "dotdot", TRACE_FILE_TXT_SUFFIX }; | ||
| 332 | + int32_t fd = -1; | ||
| 333 | + auto ret = TraceRecorderGetFd(&dirInfo, &fileInfo, &fd); | ||
| 334 | + ASSERT_EQ(TRACE_SUCCESS, ret); | ||
| 335 | + if (fd >= 0) { | ||
| 336 | + close(fd); | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + char cwd[MAX_FILEDIR_LEN + 1U] = {0}; | ||
| 340 | + ASSERT_NE(nullptr, getcwd(cwd, sizeof(cwd))); | ||
| 341 | + std::string expectedRoot = std::string(cwd) + "/" + targetDir; | ||
| 342 | + char filePath[MAX_FULLPATH_LEN + 1U] = {0}; | ||
| 343 | + ASSERT_TRUE(BuildRecorderFilePathWithRoot(filePath, MAX_FULLPATH_LEN + 1U, expectedRoot.c_str(), | ||
| 344 | + TRACER_SCHEDULE_NAME, dirTime, TRACER_SCHEDULE_NAME, "dotdot", TRACE_FILE_TXT_SUFFIX)); | ||
| 345 | + EXPECT_EQ(0, access(filePath, F_OK)); | ||
| 346 | +} | ||
| 347 | + | ||
| 348 | +TEST_F(TraceRecorderUtest, TestRecordEnvEmptyPathFallbackToHome) | ||
| 349 | +{ | ||
| 350 | + TraceRecorderExit(); | ||
| 351 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 352 | + setenv("ASCEND_WORK_PATH", "", 1); | ||
| 353 | + ASSERT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 354 | + | ||
| 355 | + const char *dirTime = "19700101080004000003"; | ||
| 356 | + TraceDirInfo dirInfo = { TRACER_SCHEDULE_NAME, getpid(), dirTime, true }; | ||
| 357 | + TraceFileInfo fileInfo = { TRACER_SCHEDULE_NAME, "empty", TRACE_FILE_TXT_SUFFIX }; | ||
| 358 | + int32_t fd = -1; | ||
| 359 | + auto ret = TraceRecorderGetFd(&dirInfo, &fileInfo, &fd); | ||
| 360 | + ASSERT_EQ(TRACE_SUCCESS, ret); | ||
| 361 | + if (fd >= 0) { | ||
| 362 | + close(fd); | ||
| 363 | + } | ||
| 364 | + | ||
| 365 | + char filePath[MAX_FULLPATH_LEN + 1U] = {0}; | ||
| 366 | + ASSERT_TRUE(BuildRecorderFilePathWithRoot(filePath, MAX_FULLPATH_LEN + 1U, LLT_TEST_DIR "/ascend", | ||
| 367 | + TRACER_SCHEDULE_NAME, dirTime, TRACER_SCHEDULE_NAME, "empty", TRACE_FILE_TXT_SUFFIX)); | ||
| 368 | + EXPECT_EQ(0, access(filePath, F_OK)); | ||
| 369 | +} | ||
| 370 | + | ||
| 371 | +TEST_F(TraceRecorderUtest, TestRecordEnvNormalizeEmptyBufferFallbackToHome) | ||
| 372 | +{ | ||
| 373 | + TraceRecorderExit(); | ||
| 374 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 375 | + MOCKER(TraceHandleEnvString).stubs().will(invoke(TraceHandleEmptyEnvStringStub)); | ||
| 376 | + ASSERT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 377 | + GlobalMockObject::verify(); | ||
| 378 | +} | ||
| 379 | + | ||
| 380 | +TEST_F(TraceRecorderUtest, TestRecordEnvRelativePathGetcwdFailedFallbackToHome) | ||
| 381 | +{ | ||
| 382 | + TraceRecorderExit(); | ||
| 383 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 384 | + setenv("ASCEND_WORK_PATH", "trace_recorder_getcwd_failed_path", 1); | ||
| 385 | + MOCKER(getcwd).stubs().will(returnValue((char *)nullptr)); | ||
| 386 | + ASSERT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 387 | + GlobalMockObject::verify(); | ||
| 388 | +} | ||
| 389 | + | ||
| 390 | +TEST_F(TraceRecorderUtest, TestRecordEnvRelativePathCopyFailedFallbackToHome) | ||
| 391 | +{ | ||
| 392 | + TraceRecorderExit(); | ||
| 393 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 394 | + g_strcpyCallIndex.store(0U); | ||
| 395 | + MOCKER(TraceHandleEnvString).stubs().will(invoke(TraceHandleRelativeEnvStringStub)); | ||
| 396 | + MOCKER(strcpy_s).stubs().will(invoke(StrcpyFailOnceThenCopy)); | ||
| 397 | + ASSERT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 398 | + GlobalMockObject::verify(); | ||
| 399 | +} | ||
| 400 | + | ||
| 401 | +TEST_F(TraceRecorderUtest, TestRecordEnvRelativePathMaxLengthInitSucceeds) | ||
| 402 | +{ | ||
| 403 | + TraceRecorderExit(); | ||
| 404 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 405 | + char cwd[MAX_FILEDIR_LEN + 1U] = {0}; | ||
| 406 | + ASSERT_NE(nullptr, getcwd(cwd, sizeof(cwd))); | ||
| 407 | + ASSERT_LT(strlen(cwd) + 1U, static_cast<size_t>(MAX_FILEDIR_LEN)); | ||
| 408 | + size_t relativeLen = static_cast<size_t>(MAX_FILEDIR_LEN) - strlen(cwd) - 1U; | ||
| 409 | + std::string relativeDir(relativeLen, 'a'); | ||
| 410 | + envGuard.AddPath(relativeDir); | ||
| 411 | + setenv("ASCEND_WORK_PATH", relativeDir.c_str(), 1); | ||
| 412 | + EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 413 | + EXPECT_EQ(0, access(relativeDir.c_str(), F_OK)); | ||
| 414 | +} | ||
| 415 | + | ||
| 416 | +TEST_F(TraceRecorderUtest, TestRecordEnvRelativePathTooLongFallbackToHome) | ||
| 417 | +{ | ||
| 418 | + TraceRecorderExit(); | ||
| 419 | + ScopedEnvAndPathCleanup envGuard("ASCEND_WORK_PATH"); | ||
| 420 | + char cwd[MAX_FILEDIR_LEN + 1U] = {0}; | ||
| 421 | + ASSERT_NE(nullptr, getcwd(cwd, sizeof(cwd))); | ||
| 422 | + ASSERT_LT(strlen(cwd), static_cast<size_t>(MAX_FILEDIR_LEN)); | ||
| 423 | + size_t relativeLen = static_cast<size_t>(MAX_FILEDIR_LEN) - strlen(cwd) + 1U; | ||
| 424 | + std::string relativeDir(relativeLen, 'b'); | ||
| 425 | + envGuard.AddPath(relativeDir); | ||
| 426 | + setenv("ASCEND_WORK_PATH", relativeDir.c_str(), 1); | ||
| 427 | + EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | ||
| 428 | + EXPECT_NE(0, access(relativeDir.c_str(), F_OK)); | ||
| 429 | +} | ||
| 430 | + | ||
| 431 | +TEST_F(TraceRecorderUtest, TestRecordEnvInvalidPath) | ||
| 432 | +{ | ||
| 433 | + printf("path doesn't exist, then create it successfully.\n"); | ||
| 434 | + TraceRecorderExit(); | ||
| 435 | + setenv("ASCEND_WORK_PATH", LLT_TEST_DIR "/env/", 1); | ||
| 215 | EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit()); | 436 | EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit()); |
| 216 | 437 | ||
| 217 | printf("path doesn't exist, then create it failed.\n"); | 438 | printf("path doesn't exist, then create it failed.\n"); |


级别:一般 问题:TraceNormalizeEnvPath 直接访问 envDir[0],未对 envDir 为 NULL 或 len 为 0 的情况做防御性校验。 影响:若上游调用者传入 NULL(例如 getenv 失败回填的指针)或 len==0,将触发空指针解引用或越界读,导致进程崩溃。 修复建议:在函数入口增加 if (envDir == NULL || len == 0) { return TRACE_FAILURE; } 校验。