Skip to content

Commit 175941a

Browse files
authored
Validate define node values (#1166)
1 parent 14e321c commit 175941a

File tree

5 files changed

+171
-16
lines changed

5 files changed

+171
-16
lines changed

tools/projmgr/include/ProjMgrYamlParser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ class ProjMgrYamlParser {
275275
protected:
276276
bool ParseCbuildPack(const std::string& input, CbuildPackItem& cbuildPack, bool checkSchema);
277277
void ParseMisc(const YAML::Node& parent, std::vector<MiscItem>& misc);
278-
void ParseDefine(const YAML::Node& defineNode, std::vector<std::string>& define);
278+
bool ParseDefine(const YAML::Node& defineNode, std::vector<std::string>& define);
279279
void ParsePacks(const YAML::Node& parent, const std::string& file, std::vector<PackItem>& packs);
280280
void ParseResolvedPacks(const YAML::Node& parent, std::vector<ResolvedPackItem>& resolvedPacks);
281281
void ParseProcessor(const YAML::Node& parent, ProcessorItem& processor);

tools/projmgr/schemas/common.schema.json

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,19 @@
361361
"oneOf": [
362362
{
363363
"type": "object",
364-
"properties": {
365-
"key": { "type": "string" },
366-
"value": { "type": ["number", "string"], "minLength": 1 }
364+
"patternProperties": {
365+
"^.*$": {
366+
"oneOf": [
367+
{
368+
"type": "string",
369+
"pattern": "^([^=:]+)$",
370+
"minLength": 1
371+
},
372+
{
373+
"type": "number"
374+
}
375+
]
376+
}
367377
}
368378
},
369379
{
@@ -383,9 +393,19 @@
383393
"oneOf": [
384394
{
385395
"type": "object",
386-
"properties": {
387-
"key": { "type": "string" },
388-
"value": { "type": ["number", "string"], "minLength": 1 }
396+
"patternProperties": {
397+
"^.*$": {
398+
"oneOf": [
399+
{
400+
"type": "string",
401+
"pattern": "^([^=:]+)$",
402+
"minLength": 1
403+
},
404+
{
405+
"type": "number"
406+
}
407+
]
408+
}
389409
}
390410
},
391411
{
@@ -405,9 +425,19 @@
405425
"oneOf": [
406426
{
407427
"type": "object",
408-
"properties": {
409-
"key": { "type": "string" },
410-
"value": { "type": ["number", "string"], "minLength": 1 }
428+
"patternProperties": {
429+
"^.*$": {
430+
"oneOf": [
431+
{
432+
"type": "string",
433+
"pattern": "^([^=:]+)$",
434+
"minLength": 1
435+
},
436+
{
437+
"type": "number"
438+
}
439+
]
440+
}
411441
}
412442
},
413443
{

tools/projmgr/src/ProjMgrYamlParser.cpp

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,43 @@ void ProjMgrYamlParser::ParseVector(const YAML::Node& parent, const string& key,
391391
}
392392
}
393393

394-
void ProjMgrYamlParser::ParseDefine(const YAML::Node& defineNode, vector<string>& define) {
394+
bool ProjMgrYamlParser::ParseDefine(const YAML::Node& defineNode, vector<string>& define) {
395+
auto ValidateDefineStr = [&](const std::string& defineValue) -> bool {
396+
if (defineValue.empty()) {
397+
return true;
398+
}
399+
400+
const std::string escapedQuote = "\\\"";
401+
int numQuotes = RteUtils::CountDelimiters(defineValue, "\"");
402+
if (numQuotes == 0) {
403+
return true;
404+
}
405+
406+
bool isValid = true;
407+
string errStr;
408+
if (numQuotes == 2) {
409+
if (defineValue.front() == '"') {
410+
isValid = (defineValue.back() == '"');
411+
}
412+
else if (defineValue.substr(0, 2) == escapedQuote) {
413+
isValid = (defineValue.substr(defineValue.size() - 2, 2) == escapedQuote);
414+
}
415+
else {
416+
isValid = false;
417+
}
418+
}
419+
else {
420+
isValid = false;
421+
}
422+
423+
if (!isValid) {
424+
ProjMgrLogger::Get().Error("invalid define: " + defineValue + ", improper quotes");
425+
}
426+
427+
return isValid;
428+
};
429+
430+
bool success = true;
395431
if (defineNode.IsDefined() && defineNode.IsSequence()) {
396432
for (const auto& item : defineNode) {
397433
// accept map elements <string, string> or a string
@@ -402,15 +438,22 @@ void ProjMgrYamlParser::ParseDefine(const YAML::Node& defineNode, vector<string>
402438
if (YAML::IsNullString(element.second)) {
403439
element.second = "";
404440
}
405-
define.push_back(element.first + "=" + element.second);
441+
success = ValidateDefineStr(element.second);
442+
if (success) {
443+
define.push_back(element.first + "=" + element.second);
444+
}
406445
}
407446
}
408447
else {
409-
define.push_back(item.as<string>());
448+
success = ValidateDefineStr(item.as<string>());
449+
if (success) {
450+
define.push_back(item.as<string>());
451+
}
410452
}
411453
}
412454
}
413455
}
456+
return success;
414457
}
415458

416459
void ProjMgrYamlParser::ParseVectorOfStringPairs(const YAML::Node& parent, const string& key, vector<pair<string, string>>& value) {
@@ -869,7 +912,9 @@ bool ProjMgrYamlParser::ParseLinker(const YAML::Node& parent, const string& file
869912
return false;
870913
}
871914
linkerItem.autoGen = linkerEntry[YAML_AUTO].IsDefined();
872-
ParseDefine(linkerEntry[YAML_DEFINE], linkerItem.defines);
915+
if (!ParseDefine(linkerEntry[YAML_DEFINE], linkerItem.defines)) {
916+
return false;
917+
}
873918
ParseVectorOrString(linkerEntry, YAML_FORCOMPILER, linkerItem.forCompiler);
874919
ParsePortablePath(linkerEntry, file, YAML_REGIONS, linkerItem.regions);
875920
ParsePortablePath(linkerEntry, file, YAML_SCRIPT, linkerItem.script);
@@ -918,8 +963,12 @@ bool ProjMgrYamlParser::ParseBuildType(const YAML::Node& parent, const string& f
918963
}
919964
ParseProcessor(parent, buildType.processor);
920965
ParseMisc(parent, buildType.misc);
921-
ParseDefine(parent[YAML_DEFINE], buildType.defines);
922-
ParseDefine(parent[YAML_DEFINE_ASM], buildType.definesAsm);
966+
if (!ParseDefine(parent[YAML_DEFINE], buildType.defines)) {
967+
return false;
968+
}
969+
if (!ParseDefine(parent[YAML_DEFINE_ASM], buildType.definesAsm)) {
970+
return false;
971+
}
923972
ParseVector(parent, YAML_UNDEFINE, buildType.undefines);
924973
ParsePortablePaths(parent, file, YAML_ADDPATH, buildType.addpaths);
925974
ParsePortablePaths(parent, file, YAML_ADDPATH_ASM, buildType.addpathsAsm);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Open-CMSIS-Pack/devtools/main/tools/projmgr/schemas/csolution.schema.json
2+
3+
solution:
4+
description: test description string
5+
target-types:
6+
- type: CM0
7+
device: RteTest_ARMCM0
8+
9+
build-types:
10+
- type: Debug
11+
compiler: AC6
12+
13+
packs:
14+
- pack: ARM::[email protected]
15+
16+
projects:
17+
- project: ./TestProject1/test1.cproject.yml
18+
19+
define:
20+
- __SAME70Q21__
21+
- __test__
22+
- "Test 1"
23+
- \"Test 3\"
24+
- Test4
25+
- KEY1: 1
26+
- KEY2: "valid"
27+
- KEY3: \"valid\"
28+
- \"No_ending_escape_quotes
29+
- Escape_quotes_in_\"middle\"
30+
- \"Invalid_ending"\
31+
- KEY4: \"No_ending_escape_quotes
32+
- KEY5: \"sam.h\
33+
- KEY6: Invalid_equal=character
34+
- KEY7: Invalid_colon:character
35+
- KEY8: \"Invalid_ending"\
36+
- KEY9: No_Starting_escaped_quotes\"
37+
- KEY10: \"Mixed_quotes"
38+
39+
define-asm:
40+
- DEF_ASM_SOLUTION

tools/projmgr/test/src/ProjMgrUnitTests.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6679,3 +6679,39 @@ TEST_F(ProjMgrUnitTests, TestRunDebug) {
66796679
ProjMgrTestEnv::CompareFile(testoutput_folder + "/run-debug+TestHW2.cbuild.yml",
66806680
testinput_folder + "/TestRunDebug/ref/run-debug+TestHW2.cbuild.yml");
66816681
}
6682+
6683+
TEST_F(ProjMgrUnitTests, Test_Check_Define_Value_With_Quotes) {
6684+
StdStreamRedirect streamRedirect;
6685+
char* argv[6];
6686+
const string& csolution = testinput_folder + "/TestSolution/test_invalid_defines.csolution.yml";
6687+
argv[1] = (char*)"convert";
6688+
argv[2] = (char*)csolution.c_str();
6689+
argv[3] = (char*)"-o";
6690+
argv[4] = (char*)testoutput_folder.c_str();
6691+
6692+
// Test1: Check schema error
6693+
string expected = "\
6694+
.*test_invalid_defines.csolution.yml:33:7 - error csolution: schema check failed, verify syntax\n\
6695+
.*test_invalid_defines.csolution.yml:34:7 - error csolution: schema check failed, verify syntax\n\
6696+
";
6697+
EXPECT_EQ(1, RunProjMgr(5, argv, m_envp));
6698+
string errStr = streamRedirect.GetErrorString();
6699+
EXPECT_TRUE(regex_search(errStr, regex(expected)));
6700+
6701+
//Test2: Check Parsing errors
6702+
streamRedirect.ClearStringStreams();
6703+
expected = "\
6704+
error csolution: invalid define: \\\"No_ending_escape_quotes, improper quotes\n\
6705+
error csolution: invalid define: Escape_quotes_in_\\\"middle\\\", improper quotes\n\
6706+
error csolution: invalid define: \\\"Invalid_ending\"\\, improper quotes\n\
6707+
error csolution: invalid define: \\\"No_ending_escape_quotes, improper quotes\n\
6708+
error csolution: invalid define: \\\"sam.h\\, improper quotes\n\
6709+
error csolution: invalid define: \\\"Invalid_ending\"\\, improper quotes\n\
6710+
error csolution: invalid define: No_Starting_escaped_quotes\\\", improper quotes\n\
6711+
error csolution: invalid define: \\\"Mixed_quotes\", improper quotes\n\
6712+
";
6713+
argv[5] = (char*)"-n";
6714+
EXPECT_EQ(1, RunProjMgr(6, argv, m_envp));
6715+
errStr = streamRedirect.GetErrorString();
6716+
EXPECT_EQ(errStr, expected);
6717+
}

0 commit comments

Comments
 (0)