fix(query)[TD-32415]. Replace memory-unsafe functions

- Replace memory unsafe functions with secure alternatives
- Fix automatical generation of subtable names
This commit is contained in:
Jinqing Kuang 2024-10-08 11:12:57 +08:00
parent fc05f92fc9
commit 0199c8dddf
5 changed files with 192 additions and 46 deletions

View File

@ -277,7 +277,7 @@ int32_t buildSubmitReqFromDataBlock(SSubmitReq2** pReq, const SSDataBlock* pData
bool alreadyAddGroupId(char* ctbName, int64_t groupId); bool alreadyAddGroupId(char* ctbName, int64_t groupId);
bool isAutoTableName(char* ctbName); bool isAutoTableName(char* ctbName);
void buildCtbNameAddGroupId(const char* stbName, char* ctbName, uint64_t groupId); int32_t buildCtbNameAddGroupId(const char* stbName, char* ctbName, uint64_t groupId, size_t cap);
int32_t buildCtbNameByGroupId(const char* stbName, uint64_t groupId, char** pName); int32_t buildCtbNameByGroupId(const char* stbName, uint64_t groupId, char** pName);
int32_t buildCtbNameByGroupIdImpl(const char* stbName, uint64_t groupId, char* pBuf); int32_t buildCtbNameByGroupIdImpl(const char* stbName, uint64_t groupId, char* pBuf);

View File

@ -2446,9 +2446,11 @@ _error:
return NULL; return NULL;
} }
static char* formatTimestamp(char* buf, int32_t bufSize, int64_t val, int precision) { static int32_t formatTimestamp(char* buf, size_t cap, int64_t val, int precision) {
time_t tt; time_t tt;
int32_t ms = 0; int32_t ms = 0;
int32_t code = TSDB_CODE_SUCCESS;
int32_t lino = 0;
if (precision == TSDB_TIME_PRECISION_NANO) { if (precision == TSDB_TIME_PRECISION_NANO) {
tt = (time_t)(val / 1000000000); tt = (time_t)(val / 1000000000);
ms = val % 1000000000; ms = val % 1000000000;
@ -2460,14 +2462,6 @@ static char* formatTimestamp(char* buf, int32_t bufSize, int64_t val, int precis
ms = val % 1000; ms = val % 1000;
} }
/* comment out as it make testcases like select_with_tags.sim fail.
but in windows, this may cause the call to localtime crash if tt < 0,
need to find a better solution.
if (tt < 0) {
tt = 0;
}
*/
if (tt <= 0 && ms < 0) { if (tt <= 0 && ms < 0) {
tt--; tt--;
if (precision == TSDB_TIME_PRECISION_NANO) { if (precision == TSDB_TIME_PRECISION_NANO) {
@ -2479,20 +2473,35 @@ static char* formatTimestamp(char* buf, int32_t bufSize, int64_t val, int precis
} }
} }
struct tm ptm = {0}; struct tm ptm = {0};
if (taosLocalTime(&tt, &ptm, buf, bufSize) == NULL) { if (taosLocalTime(&tt, &ptm, buf, cap) == NULL) {
return buf; code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
} }
size_t pos = strftime(buf, bufSize, "%Y-%m-%d %H:%M:%S", &ptm); size_t pos = strftime(buf, cap, "%Y-%m-%d %H:%M:%S", &ptm);
if (pos == 0) {
code = TSDB_CODE_OUT_OF_BUFFER;
TSDB_CHECK_CODE(code, lino, _end);
}
int32_t nwritten = 0;
if (precision == TSDB_TIME_PRECISION_NANO) { if (precision == TSDB_TIME_PRECISION_NANO) {
sprintf(buf + pos, ".%09d", ms); nwritten = snprintf(buf + pos, cap - pos, ".%09d", ms);
} else if (precision == TSDB_TIME_PRECISION_MICRO) { } else if (precision == TSDB_TIME_PRECISION_MICRO) {
sprintf(buf + pos, ".%06d", ms); nwritten = snprintf(buf + pos, cap - pos, ".%06d", ms);
} else { } else {
sprintf(buf + pos, ".%03d", ms); nwritten = snprintf(buf + pos, cap - pos, ".%03d", ms);
} }
return buf; if (nwritten >= cap - pos) {
code = TSDB_CODE_OUT_OF_BUFFER;
TSDB_CHECK_CODE(code, lino, _end);
}
_end:
if (code != TSDB_CODE_SUCCESS) {
uError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
}
return code;
} }
// for debug // for debug
@ -2543,7 +2552,10 @@ int32_t dumpBlockData(SSDataBlock* pDataBlock, const char* flag, char** pDataBuf
switch (pColInfoData->info.type) { switch (pColInfoData->info.type) {
case TSDB_DATA_TYPE_TIMESTAMP: case TSDB_DATA_TYPE_TIMESTAMP:
memset(pBuf, 0, sizeof(pBuf)); memset(pBuf, 0, sizeof(pBuf));
(void)formatTimestamp(pBuf, sizeof(pBuf), *(uint64_t*)var, pColInfoData->info.precision); code = formatTimestamp(pBuf, sizeof(pBuf), *(uint64_t*)var, pColInfoData->info.precision);
if (code != TSDB_CODE_SUCCESS) {
snprintf(pBuf, sizeof(pBuf), "NaN");
}
len += snprintf(dumpBuf + len, size - len, " %25s |", pBuf); len += snprintf(dumpBuf + len, size - len, " %25s |", pBuf);
if (len >= size - 1) goto _exit; if (len >= size - 1) goto _exit;
break; break;
@ -2857,27 +2869,98 @@ _end:
return code; return code;
} }
void buildCtbNameAddGroupId(const char* stbName, char* ctbName, uint64_t groupId) { // Construct the child table name in the form of <ctbName>_<stbName>_<groupId> and store it in `ctbName`.
char tmp[TSDB_TABLE_NAME_LEN] = {0}; // If the name length exceeds TSDB_TABLE_NAME_LEN, first convert <stbName>_<groupId> to an MD5 value and then
if (stbName == NULL){ // concatenate. If the length is still too long, convert <ctbName> to an MD5 value as well.
snprintf(tmp, TSDB_TABLE_NAME_LEN, "_%"PRIu64, groupId); int32_t buildCtbNameAddGroupId(const char* stbName, char* ctbName, uint64_t groupId, size_t cap) {
}else{ int32_t code = TSDB_CODE_SUCCESS;
int32_t lino = 0;
char tmp[TSDB_TABLE_NAME_LEN] = {0};
char* suffix = tmp;
size_t suffixCap = sizeof(tmp);
size_t suffixLen = 0;
size_t prefixLen = 0;
T_MD5_CTX context;
if (ctbName == NULL || cap < TSDB_TABLE_NAME_LEN) {
code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
}
prefixLen = strlen(ctbName);
if (stbName == NULL) {
suffixLen = snprintf(suffix, suffixCap, "%" PRIu64, groupId);
if (suffixLen >= suffixCap) {
code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
}
} else {
int32_t i = strlen(stbName) - 1; int32_t i = strlen(stbName) - 1;
for(; i >= 0; i--){ for (; i >= 0; i--) {
if (stbName[i] == '.'){ if (stbName[i] == '.') {
break; break;
} }
} }
snprintf(tmp, TSDB_TABLE_NAME_LEN, "_%s_%"PRIu64, stbName + i + 1, groupId); suffixLen = snprintf(suffix, suffixCap, "%s_%" PRIu64, stbName + i + 1, groupId);
} if (suffixLen >= suffixCap) {
suffixCap = suffixLen + 1;
ctbName[TSDB_TABLE_NAME_LEN - strlen(tmp) - 1] = 0; // put stbname + groupId to the end suffix = taosMemoryMalloc(suffixCap);
(void)strcat(ctbName, tmp); TSDB_CHECK_NULL(suffix, code, lino, _end, TSDB_CODE_OUT_OF_MEMORY);
for(int i = 0; i < strlen(ctbName); i++){ suffixLen = snprintf(suffix, suffixCap, "%s_%" PRIu64, stbName + i + 1, groupId);
if(ctbName[i] == '.'){ if (suffixLen >= suffixCap) {
ctbName[i] = '_'; code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
}
} }
} }
if (prefixLen + suffixLen + 1 >= TSDB_TABLE_NAME_LEN) {
// If the name length exceeeds the limit, convert the suffix to MD5 value.
tMD5Init(&context);
tMD5Update(&context, (uint8_t*)suffix, suffixLen);
tMD5Final(&context);
suffixLen = snprintf(suffix, suffixCap, "%016" PRIx64 "%016" PRIx64, *(uint64_t*)context.digest,
*(uint64_t*)(context.digest + 8));
if (suffixLen >= suffixCap) {
code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
}
}
if (prefixLen + suffixLen + 1 >= TSDB_TABLE_NAME_LEN) {
// If the name is still too long, convert the ctbName to MD5 value.
tMD5Init(&context);
tMD5Update(&context, (uint8_t*)ctbName, prefixLen);
tMD5Final(&context);
prefixLen = snprintf(ctbName, cap, "t_%016" PRIx64 "%016" PRIx64, *(uint64_t*)context.digest,
*(uint64_t*)(context.digest + 8));
if (prefixLen >= cap) {
code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
}
}
if (prefixLen + suffixLen + 1 >= TSDB_TABLE_NAME_LEN) {
code = TSDB_CODE_INTERNAL_ERROR;
TSDB_CHECK_CODE(code, lino, _end);
}
ctbName[prefixLen] = '_';
tstrncpy(&ctbName[prefixLen + 1], suffix, cap - prefixLen - 1);
for (char* p = ctbName; *p; ++p) {
if (*p == '.') *p = '_';
}
_end:
if (code != TSDB_CODE_SUCCESS) {
uError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
}
if (suffix != tmp) {
taosMemoryFree(suffix);
}
return code;
} }
// auto stream subtable name starts with 't_', followed by the first segment of MD5 digest for group vals. // auto stream subtable name starts with 't_', followed by the first segment of MD5 digest for group vals.

View File

@ -480,7 +480,7 @@ TEST(testCase, StreamAllNormTest) {
char ctbName[TSDB_TABLE_NAME_LEN] = {0}; char ctbName[TSDB_TABLE_NAME_LEN] = {0};
uint64_t groupId = 12345; uint64_t groupId = 12345;
buildCtbNameAddGroupId(NULL, ctbName, groupId); buildCtbNameAddGroupId(NULL, ctbName, groupId, sizeof(ctbName));
ASSERT_STREQ("_12345", ctbName); ASSERT_STREQ("_12345", ctbName);
} }
@ -490,7 +490,7 @@ TEST(testCase, StreamWithStbName) {
char ctbName[TSDB_TABLE_NAME_LEN] = {0}; char ctbName[TSDB_TABLE_NAME_LEN] = {0};
uint64_t groupId = 12345; uint64_t groupId = 12345;
buildCtbNameAddGroupId(stbName, ctbName, groupId); buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName));
ASSERT_STREQ("_stb_12345", ctbName); ASSERT_STREQ("_stb_12345", ctbName);
} }
@ -500,7 +500,7 @@ TEST(testCase, StreamWithoutDotInStbName) {
char ctbName[TSDB_TABLE_NAME_LEN] = {0}; char ctbName[TSDB_TABLE_NAME_LEN] = {0};
uint64_t groupId = 12345; uint64_t groupId = 12345;
buildCtbNameAddGroupId(stbName, ctbName, groupId); buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName));
ASSERT_STREQ("_table_12345", ctbName); ASSERT_STREQ("_table_12345", ctbName);
} }
@ -510,11 +510,59 @@ TEST(testCase, StreamWithoutDotInStbName2) {
char ctbName[TSDB_TABLE_NAME_LEN] = {0}; char ctbName[TSDB_TABLE_NAME_LEN] = {0};
uint64_t groupId = 12345; uint64_t groupId = 12345;
buildCtbNameAddGroupId(stbName, ctbName, groupId); buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName));
ASSERT_STREQ("__12345", ctbName); ASSERT_STREQ("__12345", ctbName);
} }
TEST(testCase, StreamWithLongStbName) {
char ctbName[TSDB_TABLE_NAME_LEN];
char expectName[TSDB_TABLE_NAME_LEN];
char *stbName = "a_simle_stb_name";
uint64_t groupId = UINT64_MAX;
// test basic function
strcpy(ctbName, "a_simple_ctb_name");
EXPECT_EQ(buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName)), TSDB_CODE_SUCCESS);
EXPECT_STREQ(ctbName, "a_simple_ctb_name_a_simle_stb_name_18446744073709551615");
// test null stbName
strcpy(ctbName, "a_simple_ctb_name");
stbName = NULL;
EXPECT_EQ(buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName)), TSDB_CODE_SUCCESS);
EXPECT_STREQ(ctbName, "a_simple_ctb_name_18446744073709551615");
// test buffer capcity check
EXPECT_EQ(buildCtbNameAddGroupId(stbName, NULL, groupId, sizeof(ctbName)), TSDB_CODE_INTERNAL_ERROR);
EXPECT_EQ(buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName) - 1), TSDB_CODE_INTERNAL_ERROR);
// test md5 conversion of stbName with groupid
for (int32_t i = 0; i < 159; ++i) ctbName[i] = 'A';
ctbName[159] = '\0';
stbName = taosStrdup(ctbName);
snprintf(expectName, TSDB_TABLE_NAME_LEN, "%s_d85f0d87946d76eeedd7b7b78b7492a2", ctbName);
EXPECT_EQ(buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName)), TSDB_CODE_SUCCESS);
EXPECT_STREQ(ctbName, expectName);
// test md5 conversion of all parts
for (int32_t i = 0; i < 190; ++i) ctbName[i] = 'A';
ctbName[190] = '\0';
tstrncpy(expectName, "t_d38a8b2df999bef0082ffc80a59a9cd7_d85f0d87946d76eeedd7b7b78b7492a2", TSDB_TABLE_NAME_LEN);
EXPECT_EQ(buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName)), TSDB_CODE_SUCCESS);
EXPECT_STREQ(ctbName, expectName);
// test larger stbName
taosMemoryFree(stbName);
for (int32_t i = 0; i < 190; ++i) ctbName[i] = 'A';
ctbName[190] = '\0';
stbName = taosStrdup(ctbName);
tstrncpy(expectName, "t_d38a8b2df999bef0082ffc80a59a9cd7_9c99cc7c52073b63fb750af402d9b84b", TSDB_TABLE_NAME_LEN);
EXPECT_EQ(buildCtbNameAddGroupId(stbName, ctbName, groupId, sizeof(ctbName)), TSDB_CODE_SUCCESS);
EXPECT_STREQ(ctbName, expectName);
taosMemoryFree(stbName);
}
#if 1 #if 1
TEST(testCase, NoneTest) { TEST(testCase, NoneTest) {
const static int nCols = 14; const static int nCols = 14;

View File

@ -73,14 +73,19 @@ int32_t tqBuildDeleteReq(STQ* pTq, const char* stbFullName, const SSDataBlock* p
} }
if (varTbName != NULL && varTbName != (void*)-1) { if (varTbName != NULL && varTbName != (void*)-1) {
name = taosMemoryCalloc(1, TSDB_TABLE_NAME_LEN); size_t cap = TMAX(TSDB_TABLE_NAME_LEN, varDataLen(varTbName) + 1);
name = taosMemoryMalloc(cap);
if (name == NULL) { if (name == NULL) {
return terrno; return terrno;
} }
memcpy(name, varDataVal(varTbName), varDataLen(varTbName)); memcpy(name, varDataVal(varTbName), varDataLen(varTbName));
name[varDataLen(varTbName)] = '\0';
if (newSubTableRule && !isAutoTableName(name) && !alreadyAddGroupId(name, groupId) && groupId != 0 && stbFullName) { if (newSubTableRule && !isAutoTableName(name) && !alreadyAddGroupId(name, groupId) && groupId != 0 && stbFullName) {
buildCtbNameAddGroupId(stbFullName, name, groupId); int32_t code = buildCtbNameAddGroupId(stbFullName, name, groupId, cap);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
} }
} else if (stbFullName) { } else if (stbFullName) {
int32_t code = buildCtbNameByGroupId(stbFullName, groupId, &name); int32_t code = buildCtbNameByGroupId(stbFullName, groupId, &name);
@ -236,7 +241,10 @@ int32_t setCreateTableMsgTableName(SVCreateTbReq* pCreateTableReq, SSDataBlock*
} }
strcpy(pCreateTableReq->name, pDataBlock->info.parTbName); strcpy(pCreateTableReq->name, pDataBlock->info.parTbName);
buildCtbNameAddGroupId(stbFullName, pCreateTableReq->name, gid); int32_t code = buildCtbNameAddGroupId(stbFullName, pCreateTableReq->name, gid, TSDB_TABLE_NAME_LEN);
if (code != TSDB_CODE_SUCCESS) {
return code;
}
// tqDebug("gen name from:%s", pDataBlock->info.parTbName); // tqDebug("gen name from:%s", pDataBlock->info.parTbName);
} else { } else {
pCreateTableReq->name = taosStrdup(pDataBlock->info.parTbName); pCreateTableReq->name = taosStrdup(pDataBlock->info.parTbName);
@ -852,9 +860,12 @@ int32_t setDstTableDataUid(SVnode* pVnode, SStreamTask* pTask, SSDataBlock* pDat
!alreadyAddGroupId(dstTableName, groupId) && groupId != 0) { !alreadyAddGroupId(dstTableName, groupId) && groupId != 0) {
tqDebug("s-task:%s append groupId:%" PRId64 " for generated dstTable:%s", id, groupId, dstTableName); tqDebug("s-task:%s append groupId:%" PRId64 " for generated dstTable:%s", id, groupId, dstTableName);
if (pTask->ver == SSTREAM_TASK_SUBTABLE_CHANGED_VER) { if (pTask->ver == SSTREAM_TASK_SUBTABLE_CHANGED_VER) {
buildCtbNameAddGroupId(NULL, dstTableName, groupId); code = buildCtbNameAddGroupId(NULL, dstTableName, groupId, sizeof(pDataBlock->info.parTbName));
} else if (pTask->ver > SSTREAM_TASK_SUBTABLE_CHANGED_VER && stbFullName) { } else if (pTask->ver > SSTREAM_TASK_SUBTABLE_CHANGED_VER && stbFullName) {
buildCtbNameAddGroupId(stbFullName, dstTableName, groupId); code = buildCtbNameAddGroupId(stbFullName, dstTableName, groupId, sizeof(pDataBlock->info.parTbName));
}
if (code != TSDB_CODE_SUCCESS) {
return code;
} }
} }
} }

View File

@ -706,9 +706,13 @@ int32_t streamSearchAndAddBlock(SStreamTask* pTask, SStreamDispatchReq* pReqs, S
if (pTask->subtableWithoutMd5 != 1 && !isAutoTableName(pDataBlock->info.parTbName) && if (pTask->subtableWithoutMd5 != 1 && !isAutoTableName(pDataBlock->info.parTbName) &&
!alreadyAddGroupId(pDataBlock->info.parTbName, groupId) && groupId != 0) { !alreadyAddGroupId(pDataBlock->info.parTbName, groupId) && groupId != 0) {
if (pTask->ver == SSTREAM_TASK_SUBTABLE_CHANGED_VER) { if (pTask->ver == SSTREAM_TASK_SUBTABLE_CHANGED_VER) {
buildCtbNameAddGroupId(NULL, pDataBlock->info.parTbName, groupId); code = buildCtbNameAddGroupId(NULL, pDataBlock->info.parTbName, groupId, sizeof(pDataBlock->info.parTbName));
} else if (pTask->ver > SSTREAM_TASK_SUBTABLE_CHANGED_VER) { } else if (pTask->ver > SSTREAM_TASK_SUBTABLE_CHANGED_VER) {
buildCtbNameAddGroupId(pTask->outputInfo.shuffleDispatcher.stbFullName, pDataBlock->info.parTbName, groupId); code = buildCtbNameAddGroupId(pTask->outputInfo.shuffleDispatcher.stbFullName, pDataBlock->info.parTbName,
groupId, sizeof(pDataBlock->info.parTbName));
}
if (code != TSDB_CODE_SUCCESS) {
return code;
} }
} }
} else { } else {