[VFS] Guard against null key/value nodes when parsing YAML overlay (#190506)
When a VFS overlay YAML file contains malformed content such as tabs, the YAML parser can produce KeyValueNode entries where `getKey` returns nullptr. The VFS overlay parser then passes the nullptr to `parseScalarString`, which then calls dyn_cast. Switch to `dyn_cast_if_present` for the above callsites and a few more.
This commit is contained in:
parent
04e2be73a6
commit
412d6941e3
@ -773,7 +773,8 @@ parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle,
|
||||
|
||||
for (auto &NextMapping : *Mappings) {
|
||||
/// The keys should be strings, which represent a source-file path.
|
||||
auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey());
|
||||
auto *Key =
|
||||
dyn_cast_if_present<llvm::yaml::ScalarNode>(NextMapping.getKey());
|
||||
if (!Key)
|
||||
return WrongFormatError(NextMapping.getKey());
|
||||
|
||||
@ -792,7 +793,8 @@ parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle,
|
||||
|
||||
/// The values should be sequences of strings, each representing a part of
|
||||
/// the invocation.
|
||||
auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue());
|
||||
auto *Args =
|
||||
dyn_cast_if_present<llvm::yaml::SequenceNode>(NextMapping.getValue());
|
||||
if (!Args)
|
||||
return WrongFormatError(NextMapping.getValue());
|
||||
|
||||
|
||||
@ -347,7 +347,8 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
|
||||
llvm::yaml::ScalarNode *File = nullptr;
|
||||
llvm::yaml::ScalarNode *Output = nullptr;
|
||||
for (auto& NextKeyValue : *Object) {
|
||||
auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
|
||||
auto *KeyString =
|
||||
dyn_cast_if_present<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
|
||||
if (!KeyString) {
|
||||
ErrorMessage = "Expected strings as key.";
|
||||
return false;
|
||||
|
||||
9
clang/test/VFS/Inputs/invalid-key.yaml
Normal file
9
clang/test/VFS/Inputs/invalid-key.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
# NOTE: This file contains an intentional tab character that triggers a YAML
|
||||
# parse failure. Do not replace tabs with spaces.
|
||||
version: 0
|
||||
redirecting-with: fallthrough
|
||||
roots:
|
||||
- type: directory-remap
|
||||
name: test
|
||||
external-contents: test
|
||||
|
||||
5
clang/test/VFS/Inputs/invalid-top-level-key.yaml
Normal file
5
clang/test/VFS/Inputs/invalid-top-level-key.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
# NOTE: This file contains an intentional tab character that triggers a YAML
|
||||
# parse failure. Do not replace tabs with spaces.
|
||||
version: 0
|
||||
redirecting-with: fallthrough
|
||||
roots: []
|
||||
@ -20,3 +20,9 @@
|
||||
// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/redirect-and-fallthrough.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXCLUSIVE-KEYS %s
|
||||
// CHECK-EXCLUSIVE-KEYS: 'fallthrough' and 'redirecting-with' are mutually exclusive
|
||||
// CHECK-EXCLUSIVE-KEYS: invalid virtual filesystem overlay file
|
||||
|
||||
// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/invalid-key.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-KEY %s
|
||||
// CHECK-INVALID-KEY: invalid virtual filesystem overlay file
|
||||
|
||||
// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/invalid-top-level-key.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-TOP %s
|
||||
// CHECK-INVALID-TOP: invalid virtual filesystem overlay file
|
||||
|
||||
@ -218,7 +218,8 @@ YAMLRemarkParser::parseRemark(yaml::Document &RemarkEntry) {
|
||||
else
|
||||
return MaybeLoc.takeError();
|
||||
} else if (KeyName == "Args") {
|
||||
auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
|
||||
auto *Args =
|
||||
dyn_cast_if_present<yaml::SequenceNode>(RemarkField.getValue());
|
||||
if (!Args)
|
||||
return error("wrong value type for key.", RemarkField);
|
||||
|
||||
@ -257,19 +258,19 @@ Expected<Type> YAMLRemarkParser::parseType(yaml::MappingNode &Node) {
|
||||
}
|
||||
|
||||
Expected<StringRef> YAMLRemarkParser::parseKey(yaml::KeyValueNode &Node) {
|
||||
if (auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey()))
|
||||
if (auto *Key = dyn_cast_if_present<yaml::ScalarNode>(Node.getKey()))
|
||||
return Key->getRawValue();
|
||||
|
||||
return error("key is not a string.", Node);
|
||||
}
|
||||
|
||||
Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
|
||||
auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
|
||||
auto *Value = dyn_cast_if_present<yaml::ScalarNode>(Node.getValue());
|
||||
yaml::BlockScalarNode *ValueBlock;
|
||||
StringRef Result;
|
||||
if (!Value) {
|
||||
// Try to parse the value as a block node.
|
||||
ValueBlock = dyn_cast<yaml::BlockScalarNode>(Node.getValue());
|
||||
ValueBlock = dyn_cast_if_present<yaml::BlockScalarNode>(Node.getValue());
|
||||
if (!ValueBlock)
|
||||
return error("expected a value of scalar type.", Node);
|
||||
Result = ValueBlock->getValue();
|
||||
@ -284,7 +285,7 @@ Expected<StringRef> YAMLRemarkParser::parseStr(yaml::KeyValueNode &Node) {
|
||||
|
||||
Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
|
||||
SmallVector<char, 4> Tmp;
|
||||
auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
|
||||
auto *Value = dyn_cast_if_present<yaml::ScalarNode>(Node.getValue());
|
||||
if (!Value)
|
||||
return error("expected a value of scalar type.", Node);
|
||||
unsigned UnsignedValue = 0;
|
||||
@ -295,7 +296,7 @@ Expected<unsigned> YAMLRemarkParser::parseUnsigned(yaml::KeyValueNode &Node) {
|
||||
|
||||
Expected<RemarkLocation>
|
||||
YAMLRemarkParser::parseDebugLoc(yaml::KeyValueNode &Node) {
|
||||
auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue());
|
||||
auto *DebugLoc = dyn_cast_if_present<yaml::MappingNode>(Node.getValue());
|
||||
if (!DebugLoc)
|
||||
return error("expected a value of mapping type.", Node);
|
||||
|
||||
|
||||
@ -1668,7 +1668,7 @@ class llvm::vfs::RedirectingFileSystemParser {
|
||||
// false on error
|
||||
bool parseScalarString(yaml::Node *N, StringRef &Result,
|
||||
SmallVectorImpl<char> &Storage) {
|
||||
const auto *S = dyn_cast<yaml::ScalarNode>(N);
|
||||
const auto *S = dyn_cast_if_present<yaml::ScalarNode>(N);
|
||||
|
||||
if (!S) {
|
||||
error(N, "expected string");
|
||||
@ -1913,7 +1913,7 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
ContentsField = CF_List;
|
||||
auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
|
||||
auto *Contents = dyn_cast_if_present<yaml::SequenceNode>(I.getValue());
|
||||
if (!Contents) {
|
||||
// FIXME: this is only for directories, what about files?
|
||||
error(I.getValue(), "expected array");
|
||||
@ -2115,7 +2115,7 @@ public:
|
||||
return false;
|
||||
|
||||
if (Key == "roots") {
|
||||
auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
|
||||
auto *Roots = dyn_cast_if_present<yaml::SequenceNode>(I.getValue());
|
||||
if (!Roots) {
|
||||
error(I.getValue(), "expected array");
|
||||
return false;
|
||||
|
||||
@ -430,7 +430,7 @@ Input::HNode *Input::createHNodes(Node *N) {
|
||||
auto mapHNode = new (MapHNodeAllocator.Allocate()) MapHNode(N);
|
||||
for (KeyValueNode &KVN : *Map) {
|
||||
Node *KeyNode = KVN.getKey();
|
||||
ScalarNode *Key = dyn_cast_or_null<ScalarNode>(KeyNode);
|
||||
ScalarNode *Key = dyn_cast_if_present<ScalarNode>(KeyNode);
|
||||
Node *Value = KVN.getValue();
|
||||
if (!Key || !Value) {
|
||||
if (!Key)
|
||||
|
||||
@ -295,13 +295,13 @@ bool RewriteMapParser::parseEntry(yaml::Stream &YS, yaml::KeyValueNode &Entry,
|
||||
SmallString<32> KeyStorage;
|
||||
StringRef RewriteType;
|
||||
|
||||
Key = dyn_cast<yaml::ScalarNode>(Entry.getKey());
|
||||
Key = dyn_cast_if_present<yaml::ScalarNode>(Entry.getKey());
|
||||
if (!Key) {
|
||||
YS.printError(Entry.getKey(), "rewrite type must be a scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
Value = dyn_cast<yaml::MappingNode>(Entry.getValue());
|
||||
Value = dyn_cast_if_present<yaml::MappingNode>(Entry.getValue());
|
||||
if (!Value) {
|
||||
YS.printError(Entry.getValue(), "rewrite descriptor must be a map");
|
||||
return false;
|
||||
@ -335,13 +335,13 @@ parseRewriteFunctionDescriptor(yaml::Stream &YS, yaml::ScalarNode *K,
|
||||
SmallString<32> ValueStorage;
|
||||
StringRef KeyValue;
|
||||
|
||||
Key = dyn_cast<yaml::ScalarNode>(Field.getKey());
|
||||
Key = dyn_cast_if_present<yaml::ScalarNode>(Field.getKey());
|
||||
if (!Key) {
|
||||
YS.printError(Field.getKey(), "descriptor key must be a scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
Value = dyn_cast<yaml::ScalarNode>(Field.getValue());
|
||||
Value = dyn_cast_if_present<yaml::ScalarNode>(Field.getValue());
|
||||
if (!Value) {
|
||||
YS.printError(Field.getValue(), "descriptor value must be a scalar");
|
||||
return false;
|
||||
@ -408,13 +408,13 @@ parseRewriteGlobalVariableDescriptor(yaml::Stream &YS, yaml::ScalarNode *K,
|
||||
SmallString<32> ValueStorage;
|
||||
StringRef KeyValue;
|
||||
|
||||
Key = dyn_cast<yaml::ScalarNode>(Field.getKey());
|
||||
Key = dyn_cast_if_present<yaml::ScalarNode>(Field.getKey());
|
||||
if (!Key) {
|
||||
YS.printError(Field.getKey(), "descriptor Key must be a scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
Value = dyn_cast<yaml::ScalarNode>(Field.getValue());
|
||||
Value = dyn_cast_if_present<yaml::ScalarNode>(Field.getValue());
|
||||
if (!Value) {
|
||||
YS.printError(Field.getValue(), "descriptor value must be a scalar");
|
||||
return false;
|
||||
@ -475,13 +475,13 @@ parseRewriteGlobalAliasDescriptor(yaml::Stream &YS, yaml::ScalarNode *K,
|
||||
SmallString<32> ValueStorage;
|
||||
StringRef KeyValue;
|
||||
|
||||
Key = dyn_cast<yaml::ScalarNode>(Field.getKey());
|
||||
Key = dyn_cast_if_present<yaml::ScalarNode>(Field.getKey());
|
||||
if (!Key) {
|
||||
YS.printError(Field.getKey(), "descriptor key must be a scalar");
|
||||
return false;
|
||||
}
|
||||
|
||||
Value = dyn_cast<yaml::ScalarNode>(Field.getValue());
|
||||
Value = dyn_cast_if_present<yaml::ScalarNode>(Field.getValue());
|
||||
if (!Value) {
|
||||
YS.printError(Field.getValue(), "descriptor value must be a scalar");
|
||||
return false;
|
||||
|
||||
@ -390,7 +390,7 @@ static void operator<<(json::OStream &W, const SymbolizedCoverage &C) {
|
||||
|
||||
static std::string parseScalarString(yaml::Node *N) {
|
||||
SmallString<64> StringStorage;
|
||||
yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
|
||||
yaml::ScalarNode *S = dyn_cast_if_present<yaml::ScalarNode>(N);
|
||||
failIf(!S, "expected string");
|
||||
return std::string(S->getValue(StringStorage));
|
||||
}
|
||||
@ -419,7 +419,7 @@ SymbolizedCoverage::read(const std::string &InputFile) {
|
||||
|
||||
if (Key == "covered-points") {
|
||||
yaml::SequenceNode *Points =
|
||||
dyn_cast<yaml::SequenceNode>(KVNode.getValue());
|
||||
dyn_cast_if_present<yaml::SequenceNode>(KVNode.getValue());
|
||||
failIf(!Points, "expected array: " + InputFile);
|
||||
|
||||
for (auto I = Points->begin(), E = Points->end(); I != E; ++I) {
|
||||
@ -429,21 +429,21 @@ SymbolizedCoverage::read(const std::string &InputFile) {
|
||||
Coverage->BinaryHash = parseScalarString(KVNode.getValue());
|
||||
} else if (Key == "point-symbol-info") {
|
||||
yaml::MappingNode *PointSymbolInfo =
|
||||
dyn_cast<yaml::MappingNode>(KVNode.getValue());
|
||||
dyn_cast_if_present<yaml::MappingNode>(KVNode.getValue());
|
||||
failIf(!PointSymbolInfo, "expected mapping node: " + InputFile);
|
||||
|
||||
for (auto &FileKVNode : *PointSymbolInfo) {
|
||||
auto Filename = parseScalarString(FileKVNode.getKey());
|
||||
|
||||
yaml::MappingNode *FileInfo =
|
||||
dyn_cast<yaml::MappingNode>(FileKVNode.getValue());
|
||||
dyn_cast_if_present<yaml::MappingNode>(FileKVNode.getValue());
|
||||
failIf(!FileInfo, "expected mapping node: " + InputFile);
|
||||
|
||||
for (auto &FunctionKVNode : *FileInfo) {
|
||||
auto FunctionName = parseScalarString(FunctionKVNode.getKey());
|
||||
|
||||
yaml::MappingNode *FunctionInfo =
|
||||
dyn_cast<yaml::MappingNode>(FunctionKVNode.getValue());
|
||||
dyn_cast_if_present<yaml::MappingNode>(FunctionKVNode.getValue());
|
||||
failIf(!FunctionInfo, "expected mapping node: " + InputFile);
|
||||
|
||||
for (auto &PointKVNode : *FunctionInfo) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user