LLVM: lib/WindowsManifest/WindowsManifestMerger.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
14#include "llvm/Config/config.h"
16
17#if LLVM_ENABLE_LIBXML2
18#include <libxml/xmlreader.h>
19#endif
20
21#define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
22#define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
23
24using namespace llvm;
26
28
30
32
34public:
37
38private:
39 static void errorCallback(void *Ctx, const char *Format, ...);
40 Error getParseError();
41#if LLVM_ENABLE_LIBXML2
42 struct XmlDeleter {
43 void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
44 void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); }
45 };
46 xmlDocPtr CombinedDoc = nullptr;
47 std::vector<std::unique_ptr<xmlDoc, XmlDeleter>> MergedDocs;
48 bool Merged = false;
49 int BufferSize = 0;
50 std::unique_ptr<xmlChar, XmlDeleter> Buffer;
51#endif
52 bool ParseErrorOccurred = false;
53};
54
55#if LLVM_ENABLE_LIBXML2
56
57static constexpr std::pair<StringLiteral, StringLiteral> MtNsHrefsPrefixes[] = {
58 {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"},
59 {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"},
60 {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"},
61 {"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
62 "ms_windowsSettings"},
63 {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}};
64
65static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
66
67
68 if ( ||
)
71}
72
73static bool isMergeableElement(const unsigned char *ElementName) {
74 for (StringRef S : {"application", "assembly", "assemblyIdentity",
75 "compatibility", "noInherit", "requestedExecutionLevel",
76 "requestedPrivileges", "security", "trustInfo"}) {
78 return true;
79 }
80 }
81 return false;
82}
83
84static xmlNodePtr getChildWithName(xmlNodePtr Parent,
85 const unsigned char *ElementName) {
86 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
87 if (xmlStringsEqual(Child->name, ElementName)) {
88 return Child;
89 }
90 }
91 return nullptr;
92}
93
94static xmlAttrPtr getAttribute(xmlNodePtr Node,
95 const unsigned char *AttributeName) {
98 if (xmlStringsEqual(Attribute->name, AttributeName)) {
100 }
101 }
102 return nullptr;
103}
104
105
106static bool namespaceOverrides(const unsigned char *HRef1,
107 const unsigned char *HRef2) {
109 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
110 return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
111 });
113 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
114 return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
115 });
116 return HRef1Position < HRef2Position;
117}
118
119
120
121
122static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
123 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
124 if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
125 return Def;
126 }
127 }
128 if (Node->parent) {
129 return search(HRef, Node->parent);
130 }
131 return nullptr;
132}
133
134
135
136static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
137 for (auto &Ns : MtNsHrefsPrefixes) {
138 if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
140 }
141 }
142 return HRef;
143}
144
145
146
147
148
149static Expected searchOrDefine(const unsigned char *HRef,
150 xmlNodePtr Node) {
151 if (xmlNsPtr Def = search(HRef, Node))
152 return Def;
153 if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
154 return Def;
156}
157
158
159
160static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
161 xmlNodePtr OriginalNode,
162 xmlAttrPtr AdditionalAttribute) {
163
164 Expected ExplicitOrError =
165 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
166 if (!ExplicitOrError)
167 return ExplicitOrError.takeError();
168 OriginalAttribute->ns = std::move(ExplicitOrError.get());
170}
171
172
173
174static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
175 xmlNodePtr Node) {
176 if (Node == nullptr)
177 return nullptr;
178 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
179 if (xmlStringsEqual(Def->prefix, Prefix)) {
180 return Def;
181 }
182 }
183 return nullptr;
184}
185
186
187
188
189static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
190 if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
191 return Ret;
192 if (Node->parent == nullptr)
193 return nullptr;
194 return getClosestDefault(Node->parent);
195}
196
197
198
199
200
201
202
204 xmlNodePtr AdditionalNode) {
205 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
208 if (xmlAttrPtr OriginalAttribute =
209 getAttribute(OriginalNode, Attribute->name)) {
210 if (!xmlStringsEqual(OriginalAttribute->children->content,
213 Twine("conflicting attributes for ") +
215 }
217 continue;
218 }
219 if (!OriginalAttribute->ns) {
220 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
222 return E;
223 }
224 continue;
225 }
226 if (namespaceOverrides(OriginalAttribute->ns->href,
228
229
230
231
232 if (!OriginalAttribute->ns->prefix && ->ns->prefix &&
233 ClosestDefault &&
234 xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
235 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
237 return E;
238 }
239 continue;
240 }
241 continue;
242
243
244
245
246 }
247 if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
248 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
249 ClosestDefault->href))) {
250 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
252 return E;
253 }
254 continue;
255 }
256 continue;
257 }
258
259
260
261
262 xmlAttrPtr NewProp =
263 xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
264 Expected ExplicitOrError =
265 searchOrDefine(Attribute->ns->href, OriginalNode);
266 if (!ExplicitOrError)
267 return ExplicitOrError.takeError();
268 NewProp->ns = std::move(ExplicitOrError.get());
269 }
271}
272
273
274static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
275
276 if (!Node1 || !Node1->ns)
277 return Node2;
278 if (!Node2 || !Node2->ns)
279 return Node1;
280 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
281 return Node1;
282 return Node2;
283}
284
285
286static bool hasInheritedNs(xmlNodePtr Node) {
287 return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
288}
289
290
291
292static bool hasInheritedDefaultNs(xmlNodePtr Node) {
293 return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
294}
295
296
297static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
298 return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
299}
300
301
302
303
304
305
306static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
307
308
309
310 if (hasDefinedDefaultNamespace(Node))
311 return;
312 if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
313 hasInheritedDefaultNs(Node))
314 Node->ns = PrefixDef;
318 xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
320 }
321 }
322 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
323 explicateNamespace(PrefixDef, Child);
324 }
325}
326
327
328static Error mergeNamespaces(xmlNodePtr OriginalNode,
329 xmlNodePtr AdditionalNode) {
330
331
332 const unsigned char *OriginalDefinedDefaultHref = nullptr;
333 if (xmlNsPtr OriginalDefinedDefaultNs =
334 getNamespaceWithPrefix(nullptr, OriginalNode)) {
335 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
336 }
337 const unsigned char *NewDefinedDefaultHref = nullptr;
338
339
340
341 for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
342 if (xmlNsPtr OriginalNsDef =
343 getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
344 if (->prefix) {
345 if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
347 }
348 } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
350 Twine("conflicting namespace definitions for ") +
352 }
353 } else {
354 xmlNsPtr NewDef = xmlCopyNamespace(Def);
355 NewDef->next = OriginalNode->nsDef;
356 OriginalNode->nsDef = NewDef;
357 }
358 }
359
360
361
362
363
364 xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
365 xmlNodePtr NonDominantNode =
366 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
367 if (DominantNode == OriginalNode) {
368 if (OriginalDefinedDefaultHref) {
369 xmlNsPtr NonDominantDefinedDefault =
370 getNamespaceWithPrefix(nullptr, NonDominantNode);
371
372
373
374
375
376
377 if (NonDominantDefinedDefault &&
378 namespaceOverrides(NonDominantDefinedDefault->href,
379 OriginalDefinedDefaultHref)) {
380 Expected EC =
381 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
382 if (!EC) {
383 return EC.takeError();
384 }
385 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
386 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
387 }
388
389
390
391
392
393
394
395 } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
396 if (DominantNode->parent) {
397 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
398 Expected EC =
399 searchOrDefine(ClosestDefault->href, DominantNode);
400 if (!EC) {
401 return EC.takeError();
402 }
403 xmlNsPtr ExplicitDefault = std::move(EC.get());
404 explicateNamespace(ExplicitDefault, DominantNode);
405 }
406 }
407 } else {
408
409
410
411 if (hasDefinedDefaultNamespace(DominantNode)) {
412 NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
413 } else {
414
415
416
417
418 Expected EC =
419 searchOrDefine(DominantNode->ns->href, NonDominantNode);
420 if (!EC) {
421 return EC.takeError();
422 }
423 xmlNsPtr Explicit = std::move(EC.get());
424 NonDominantNode->ns = Explicit;
425 }
426
427
428 if (xmlNsPtr DominantDefaultDefined =
429 getNamespaceWithPrefix(nullptr, DominantNode)) {
430 if (OriginalDefinedDefaultHref) {
431 if (namespaceOverrides(DominantDefaultDefined->href,
432 OriginalDefinedDefaultHref)) {
433
434
435
436 Expected EC =
437 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
438 if (!EC) {
439 return EC.takeError();
440 }
441 xmlNsPtr ExplicitDefault = std::move(EC.get());
442 explicateNamespace(ExplicitDefault, NonDominantNode);
443 }
444 } else {
445
446
447
448
449 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
450 Expected EC =
451 searchOrDefine(ClosestDefault->href, NonDominantNode);
452 if (!EC) {
453 return EC.takeError();
454 }
455 xmlNsPtr ExplicitDefault = std::move(EC.get());
456 explicateNamespace(ExplicitDefault, NonDominantNode);
457 }
458 }
459 }
460 if (NewDefinedDefaultHref) {
461 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
462 xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
463 OriginalNsDef->href = NewDefinedDefaultHref;
464 }
465 xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
467}
468
469static bool isRecognizedNamespace(const unsigned char *NsHref) {
470 for (auto &Ns : MtNsHrefsPrefixes) {
471 if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
472 return true;
473 }
474 }
475 return false;
476}
477
478static bool hasRecognizedNamespace(xmlNodePtr Node) {
479 return isRecognizedNamespace(Node->ns->href);
480}
481
482
483
484static Error reconcileNamespaces(xmlNodePtr Node) {
485 if (!Node) {
487 }
488 if (hasInheritedNs(Node)) {
489 Expected ExplicitOrError = searchOrDefine(Node->ns->href, Node);
490 if (!ExplicitOrError) {
491 return ExplicitOrError.takeError();
492 }
493 xmlNsPtr Explicit = std::move(ExplicitOrError.get());
494 Node->ns = Explicit;
495 }
496 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
497 if (auto E = reconcileNamespaces(Child)) {
498 return E;
499 }
500 }
502}
503
504
505
506
507static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
509 return E;
510 if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
511 return E;
512 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
513 xmlNode StoreNext;
514 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
515 xmlNodePtr OriginalChildWithName;
516 if (!isMergeableElement(Child->name) ||
517 !(OriginalChildWithName =
518 getChildWithName(OriginalRoot, Child->name)) ||
519 !hasRecognizedNamespace(Child)) {
520 StoreNext.next = Child->next;
521 xmlUnlinkNode(Child);
522 if (!xmlAddChild(OriginalRoot, Child)) {
525 }
526 if (auto E = reconcileNamespaces(Child)) {
527 return E;
528 }
529 Child = &StoreNext;
530 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
531 return E;
532 }
533 }
535}
536
537static void stripComments(xmlNodePtr Root) {
538 xmlNode StoreNext;
539 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
540 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
541 stripComments(Child);
542 continue;
543 }
544 StoreNext.next = Child->next;
545 xmlNodePtr Remove = Child;
546 Child = &StoreNext;
547 xmlUnlinkNode(Remove);
548 xmlFreeNode(Remove);
549 }
550}
551
552
553
554
555static void setAttributeNamespaces(xmlNodePtr Node) {
559 Attribute->ns = getClosestDefault(Node);
560 }
561 }
562 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
563 setAttributeNamespaces(Child);
564 }
565}
566
567
568
569static void checkAndStripPrefixes(xmlNodePtr Node,
570 std::vector &RequiredPrefixes) {
571 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
572 checkAndStripPrefixes(Child, RequiredPrefixes);
573 }
574 if (Node->ns && Node->ns->prefix != nullptr) {
575 xmlNsPtr ClosestDefault = getClosestDefault(Node);
576 if (ClosestDefault &&
577 xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
578 Node->ns = ClosestDefault;
580 RequiredPrefixes.push_back(Node->ns);
581 }
582 }
586 xmlNsPtr ClosestDefault = getClosestDefault(Node);
587 if (ClosestDefault &&
588 xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
591 RequiredPrefixes.push_back(Attribute->ns);
592 }
593 }
594 }
595 xmlNsPtr Prev;
596 xmlNs Temp;
597 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
599 Prev = Def;
600 continue;
601 }
602 if (Def == Node->nsDef) {
604 } else {
605 Prev->next = Def->next;
606 }
607 Temp.next = Def->next;
608 xmlFreeNs(Def);
609 Def = &Temp;
610 }
611}
612
614 MemoryBufferRef Manifest) {
615 if (Merged)
617 "merge after getMergedManifest is not supported");
620 "attempted to merge empty manifest");
621 xmlSetGenericErrorFunc((void *)this,
622 WindowsManifestMergerImpl::errorCallback);
623 std::unique_ptr<xmlDoc, XmlDeleter> ManifestXML(xmlReadMemory(
625 nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT));
626 xmlSetGenericErrorFunc(nullptr, nullptr);
627 if (auto E = getParseError())
628 return E;
629 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML.get());
630 stripComments(AdditionalRoot);
631 setAttributeNamespaces(AdditionalRoot);
632 if (CombinedDoc == nullptr) {
633 CombinedDoc = ManifestXML.get();
634 } else {
635 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
636 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
637 !isMergeableElement(AdditionalRoot->name) ||
638 !hasRecognizedNamespace(AdditionalRoot)) {
640 }
641 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
642 return E;
643 }
644 }
645 MergedDocs.push_back(std::move(ManifestXML));
647}
648
649std::unique_ptr
651 if (!Merged) {
652 Merged = true;
653
654 if (!CombinedDoc)
655 return nullptr;
656
657 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
658 std::vector RequiredPrefixes;
659 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
660 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
661 xmlNewDoc((const unsigned char *)"1.0"));
662 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
663 assert(nullptr == xmlDocGetRootElement(CombinedDoc));
664
665 xmlChar *Buff = nullptr;
666 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1);
667 Buffer.reset(Buff);
668 }
669
671 FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize))
672 : nullptr;
673}
674
676
677#else
678
683
684std::unique_ptr
688
690
691#endif
692
695
697
699 return Impl->merge(Manifest);
700}
701
703 return Impl->getMergedManifest();
704}
705
706void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
707 void *Ctx, const char *Format, ...) {
708 auto *Merger = (WindowsManifestMergerImpl *)Ctx;
709 Merger->ParseErrorOccurred = true;
710}
711
712Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
713 if (!ParseErrorOccurred)
716}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static void mergeAttributes(LLVMContext &Ctx, const Module &M, const DataLayout &DL, const Triple &TT, Function *Func, FunctionType *FuncTy, AttributeList FuncAttrs)
#define TO_XML_CHAR(X)
Definition WindowsManifestMerger.cpp:21
#define FROM_XML_CHAR(X)
Definition WindowsManifestMerger.cpp:22
Error merge(MemoryBufferRef Manifest)
Definition WindowsManifestMerger.cpp:679
std::unique_ptr< MemoryBuffer > getMergedManifest()
Definition WindowsManifestMerger.cpp:685
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
size_t getBufferSize() const
const char * getBufferStart() const
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class implements an extremely fast bulk output stream that can only output to a stream.
WindowsManifestError(const Twine &Msg)
Definition WindowsManifestMerger.cpp:29
void log(raw_ostream &OS) const override
Print an error message to an output stream.
Definition WindowsManifestMerger.cpp:31
LLVM_ABI WindowsManifestMerger()
Definition WindowsManifestMerger.cpp:693
LLVM_ABI ~WindowsManifestMerger()
LLVM_ABI std::unique_ptr< MemoryBuffer > getMergedManifest()
Definition WindowsManifestMerger.cpp:702
LLVM_ABI Error merge(MemoryBufferRef Manifest)
Definition WindowsManifestMerger.cpp:698
NodeAddr< DefNode * > Def
NodeAddr< NodeBase * > Node
LLVM_ABI bool isAvailable()
Definition WindowsManifestMerger.cpp:689
This is an optimization pass for GlobalISel generic memory operations.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Implement std::hash so that hash_code can be used in STL containers.