Bug Summary

File:build/source/llvm/lib/WindowsManifest/WindowsManifestMerger.cpp
Warning:line 607, column 18
Access to field 'next' results in a dereference of an undefined pointer value (loaded from variable 'Prev')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name WindowsManifestMerger.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /usr/include/libxml2 -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/WindowsManifest -I /build/source/llvm/lib/WindowsManifest -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/llvm/lib/WindowsManifest/WindowsManifestMerger.cpp
1//===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===---------------------------------------------------------------------===//
8//
9// This file implements the .manifest merger class.
10//
11//===---------------------------------------------------------------------===//
12
13#include "llvm/WindowsManifest/WindowsManifestMerger.h"
14#include "llvm/Config/config.h"
15#include "llvm/Support/MemoryBuffer.h"
16
17#if LLVM_ENABLE_LIBXML21
18#include <libxml/xmlreader.h>
19#endif
20
21#define TO_XML_CHAR(X)reinterpret_cast<const unsigned char *>(X) reinterpret_cast<const unsigned char *>(X)
22#define FROM_XML_CHAR(X)reinterpret_cast<const char *>(X) reinterpret_cast<const char *>(X)
23
24using namespace llvm;
25using namespace windows_manifest;
26
27char WindowsManifestError::ID = 0;
28
29WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
30
31void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
32
33class WindowsManifestMerger::WindowsManifestMergerImpl {
34public:
35 ~WindowsManifestMergerImpl();
36 Error merge(MemoryBufferRef Manifest);
37 std::unique_ptr<MemoryBuffer> getMergedManifest();
38
39private:
40 static void errorCallback(void *Ctx, const char *Format, ...);
41 Error getParseError();
42#if LLVM_ENABLE_LIBXML21
43 xmlDocPtr CombinedDoc = nullptr;
44 std::vector<xmlDocPtr> MergedDocs;
45
46 bool Merged = false;
47 struct XmlDeleter {
48 void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
49 void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); }
50 };
51 int BufferSize = 0;
52 std::unique_ptr<xmlChar, XmlDeleter> Buffer;
53#endif
54 bool ParseErrorOccurred = false;
55};
56
57#if LLVM_ENABLE_LIBXML21
58
59static constexpr std::pair<StringLiteral, StringLiteral> MtNsHrefsPrefixes[] = {
60 {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"},
61 {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"},
62 {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"},
63 {"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
64 "ms_windowsSettings"},
65 {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}};
66
67static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
68 // Handle null pointers. Comparison of 2 null pointers returns true because
69 // this indicates the prefix of a default namespace.
70 if (!A || !B)
71 return A == B;
72 return strcmp(FROM_XML_CHAR(A)reinterpret_cast<const char *>(A), FROM_XML_CHAR(B)reinterpret_cast<const char *>(B)) == 0;
73}
74
75static bool isMergeableElement(const unsigned char *ElementName) {
76 for (StringRef S : {"application", "assembly", "assemblyIdentity",
77 "compatibility", "noInherit", "requestedExecutionLevel",
78 "requestedPrivileges", "security", "trustInfo"}) {
79 if (S == FROM_XML_CHAR(ElementName)reinterpret_cast<const char *>(ElementName)) {
80 return true;
81 }
82 }
83 return false;
84}
85
86static xmlNodePtr getChildWithName(xmlNodePtr Parent,
87 const unsigned char *ElementName) {
88 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
89 if (xmlStringsEqual(Child->name, ElementName)) {
90 return Child;
91 }
92 }
93 return nullptr;
94}
95
96static xmlAttrPtr getAttribute(xmlNodePtr Node,
97 const unsigned char *AttributeName) {
98 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
99 Attribute = Attribute->next) {
100 if (xmlStringsEqual(Attribute->name, AttributeName)) {
101 return Attribute;
102 }
103 }
104 return nullptr;
105}
106
107// Check if namespace specified by HRef1 overrides that of HRef2.
108static bool namespaceOverrides(const unsigned char *HRef1,
109 const unsigned char *HRef2) {
110 auto HRef1Position = llvm::find_if(
111 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
112 return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data())reinterpret_cast<const unsigned char *>(Element.first.data
())
);
113 });
114 auto HRef2Position = llvm::find_if(
115 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
116 return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data())reinterpret_cast<const unsigned char *>(Element.first.data
())
);
117 });
118 return HRef1Position < HRef2Position;
119}
120
121// Search for prefix-defined namespace specified by HRef, starting on Node and
122// continuing recursively upwards. Returns the namespace or nullptr if not
123// found.
124static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
125 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
126 if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
127 return Def;
128 }
129 }
130 if (Node->parent) {
131 return search(HRef, Node->parent);
132 }
133 return nullptr;
134}
135
136// Return the prefix that corresponds to the HRef. If HRef is not a recognized
137// URI, then just return the HRef itself to use as the prefix.
138static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
139 for (auto &Ns : MtNsHrefsPrefixes) {
140 if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data())reinterpret_cast<const unsigned char *>(Ns.first.data()
)
)) {
141 return TO_XML_CHAR(Ns.second.data())reinterpret_cast<const unsigned char *>(Ns.second.data(
))
;
142 }
143 }
144 return HRef;
145}
146
147// Search for prefix-defined namespace specified by HRef, starting on Node and
148// continuing recursively upwards. If it is found, then return it. If it is
149// not found, then prefix-define that namespace on the node and return a
150// reference to it.
151static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef,
152 xmlNodePtr Node) {
153 if (xmlNsPtr Def = search(HRef, Node))
154 return Def;
155 if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
156 return Def;
157 return make_error<WindowsManifestError>("failed to create new namespace");
158}
159
160// Set the namespace of OrigionalAttribute on OriginalNode to be that of
161// AdditionalAttribute's.
162static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
163 xmlNodePtr OriginalNode,
164 xmlAttrPtr AdditionalAttribute) {
165
166 Expected<xmlNsPtr> ExplicitOrError =
167 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
168 if (!ExplicitOrError)
169 return ExplicitOrError.takeError();
170 OriginalAttribute->ns = std::move(ExplicitOrError.get());
171 return Error::success();
172}
173
174// Return the corresponding namespace definition for the prefix, defined on the
175// given Node. Returns nullptr if there is no such definition.
176static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
177 xmlNodePtr Node) {
178 if (Node == nullptr)
179 return nullptr;
180 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
181 if (xmlStringsEqual(Def->prefix, Prefix)) {
182 return Def;
183 }
184 }
185 return nullptr;
186}
187
188// Search for the closest inheritable default namespace, starting on (and
189// including) the Node and traveling upwards through parent nodes. Returns
190// nullptr if there are no inheritable default namespaces.
191static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
192 if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
193 return Ret;
194 if (Node->parent == nullptr)
195 return nullptr;
196 return getClosestDefault(Node->parent);
197}
198
199// Merge the attributes of AdditionalNode into OriginalNode. If attributes
200// with identical types are present, they are not duplicated but rather if
201// their values are not consistent and error is thrown. In addition, the
202// higher priority namespace is used for each attribute, EXCEPT in the case
203// of merging two default namespaces and the lower priority namespace
204// definition occurs closer than the higher priority one.
205static Error mergeAttributes(xmlNodePtr OriginalNode,
206 xmlNodePtr AdditionalNode) {
207 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
208 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
209 Attribute = Attribute->next) {
210 if (xmlAttrPtr OriginalAttribute =
211 getAttribute(OriginalNode, Attribute->name)) {
212 if (!xmlStringsEqual(OriginalAttribute->children->content,
213 Attribute->children->content)) {
214 return make_error<WindowsManifestError>(
215 Twine("conflicting attributes for ") +
216 FROM_XML_CHAR(OriginalNode->name)reinterpret_cast<const char *>(OriginalNode->name));
217 }
218 if (!Attribute->ns) {
219 continue;
220 }
221 if (!OriginalAttribute->ns) {
222 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
223 Attribute)) {
224 return E;
225 }
226 continue;
227 }
228 if (namespaceOverrides(OriginalAttribute->ns->href,
229 Attribute->ns->href)) {
230 // In this case, the original attribute has a higher priority namespace
231 // than the incomiing attribute, however the namespace definition of
232 // the lower priority namespace occurs first traveling upwards in the
233 // tree. Therefore the lower priority namespace is applied.
234 if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix &&
235 ClosestDefault &&
236 xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
237 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
238 Attribute)) {
239 return E;
240 }
241 continue;
242 }
243 continue;
244 // This covers the case where the incoming attribute has the higher
245 // priority. The higher priority namespace is applied in all cases
246 // EXCEPT when both of the namespaces are default inherited, and the
247 // closest inherited default is the lower priority one.
248 }
249 if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
250 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
251 ClosestDefault->href))) {
252 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
253 Attribute)) {
254 return E;
255 }
256 continue;
257 }
258 continue;
259 }
260 // If the incoming attribute is not already found on the node, append it
261 // to the end of the properties list. Also explicitly apply its
262 // namespace as a prefix because it might be contained in a separate
263 // namespace that doesn't use the attribute.
264 xmlAttrPtr NewProp =
265 xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
266 Expected<xmlNsPtr> ExplicitOrError =
267 searchOrDefine(Attribute->ns->href, OriginalNode);
268 if (!ExplicitOrError)
269 return ExplicitOrError.takeError();
270 NewProp->ns = std::move(ExplicitOrError.get());
271 }
272 return Error::success();
273}
274
275// Given two nodes, return the one with the higher priority namespace.
276static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
277
278 if (!Node1 || !Node1->ns)
279 return Node2;
280 if (!Node2 || !Node2->ns)
281 return Node1;
282 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
283 return Node1;
284 return Node2;
285}
286
287// Checks if this Node's namespace is inherited or one it defined itself.
288static bool hasInheritedNs(xmlNodePtr Node) {
289 return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
290}
291
292// Check if this Node's namespace is a default namespace that it inherited, as
293// opposed to defining itself.
294static bool hasInheritedDefaultNs(xmlNodePtr Node) {
295 return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
296}
297
298// Check if this Node's namespace is a default namespace it defined itself.
299static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
300 return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
301}
302
303// For the given explicit prefix-definition of a namespace, travel downwards
304// from a node recursively, and for every implicit, inherited default usage of
305// that namespace replace it with that explicit prefix use. This is important
306// when namespace overriding occurs when merging, so that elements unique to a
307// namespace will still stay in that namespace.
308static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
309 // If a node as its own default namespace definition it clearly cannot have
310 // inherited the given default namespace, and neither will any of its
311 // children.
312 if (hasDefinedDefaultNamespace(Node))
313 return;
314 if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
315 hasInheritedDefaultNs(Node))
316 Node->ns = PrefixDef;
317 for (xmlAttrPtr Attribute = Node->properties; Attribute;
318 Attribute = Attribute->next) {
319 if (Attribute->ns &&
320 xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
321 Attribute->ns = PrefixDef;
322 }
323 }
324 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
325 explicateNamespace(PrefixDef, Child);
326 }
327}
328
329// Perform the namespace merge between two nodes.
330static Error mergeNamespaces(xmlNodePtr OriginalNode,
331 xmlNodePtr AdditionalNode) {
332 // Save the original default namespace definition in case the incoming node
333 // overrides it.
334 const unsigned char *OriginalDefinedDefaultHref = nullptr;
335 if (xmlNsPtr OriginalDefinedDefaultNs =
336 getNamespaceWithPrefix(nullptr, OriginalNode)) {
337 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
338 }
339 const unsigned char *NewDefinedDefaultHref = nullptr;
340 // Copy all namespace definitions. There can only be one default namespace
341 // definition per node, so the higher priority one takes precedence in the
342 // case of collision.
343 for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
344 if (xmlNsPtr OriginalNsDef =
345 getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
346 if (!Def->prefix) {
347 if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
348 NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)))reinterpret_cast<const unsigned char *>(strdup(reinterpret_cast
<const char *>(Def->href)))
;
349 }
350 } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
351 return make_error<WindowsManifestError>(
352 Twine("conflicting namespace definitions for ") +
353 FROM_XML_CHAR(Def->prefix)reinterpret_cast<const char *>(Def->prefix));
354 }
355 } else {
356 xmlNsPtr NewDef = xmlCopyNamespace(Def);
357 NewDef->next = OriginalNode->nsDef;
358 OriginalNode->nsDef = NewDef;
359 }
360 }
361
362 // Check whether the original node or the incoming node has the higher
363 // priority namespace. Depending on which one is dominant, we will have
364 // to recursively apply namespace changes down to children of the original
365 // node.
366 xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
367 xmlNodePtr NonDominantNode =
368 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
369 if (DominantNode == OriginalNode) {
370 if (OriginalDefinedDefaultHref) {
371 xmlNsPtr NonDominantDefinedDefault =
372 getNamespaceWithPrefix(nullptr, NonDominantNode);
373 // In this case, both the nodes defined a default namespace. However
374 // the lower priority node ended up having a higher priority default
375 // definition. This can occur if the higher priority node is prefix
376 // namespace defined. In this case we have to define an explicit
377 // prefix for the overridden definition and apply it to all children
378 // who relied on that definition.
379 if (NonDominantDefinedDefault &&
380 namespaceOverrides(NonDominantDefinedDefault->href,
381 OriginalDefinedDefaultHref)) {
382 Expected<xmlNsPtr> EC =
383 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
384 if (!EC) {
385 return EC.takeError();
386 }
387 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
388 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
389 }
390 // In this case the node with a higher priority namespace did not have a
391 // default namespace definition, but the lower priority node did. In this
392 // case the new default namespace definition is copied. A side effect of
393 // this is that all children will suddenly find themselves in a different
394 // default namespace. To maintain correctness we need to ensure that all
395 // children now explicitly refer to the namespace that they had previously
396 // implicitly inherited.
397 } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
398 if (DominantNode->parent) {
399 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
400 Expected<xmlNsPtr> EC =
401 searchOrDefine(ClosestDefault->href, DominantNode);
402 if (!EC) {
403 return EC.takeError();
404 }
405 xmlNsPtr ExplicitDefault = std::move(EC.get());
406 explicateNamespace(ExplicitDefault, DominantNode);
407 }
408 }
409 } else {
410 // Covers case where the incoming node has a default namespace definition
411 // that overrides the original node's namespace. This always leads to
412 // the original node receiving that new default namespace.
413 if (hasDefinedDefaultNamespace(DominantNode)) {
414 NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
415 } else {
416 // This covers the case where the incoming node either has a prefix
417 // namespace, or an inherited default namespace. Since the namespace
418 // may not yet be defined in the original tree we do a searchOrDefine
419 // for it, and then set the namespace equal to it.
420 Expected<xmlNsPtr> EC =
421 searchOrDefine(DominantNode->ns->href, NonDominantNode);
422 if (!EC) {
423 return EC.takeError();
424 }
425 xmlNsPtr Explicit = std::move(EC.get());
426 NonDominantNode->ns = Explicit;
427 }
428 // This covers cases where the incoming dominant node HAS a default
429 // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
430 if (xmlNsPtr DominantDefaultDefined =
431 getNamespaceWithPrefix(nullptr, DominantNode)) {
432 if (OriginalDefinedDefaultHref) {
433 if (namespaceOverrides(DominantDefaultDefined->href,
434 OriginalDefinedDefaultHref)) {
435 // In this case, the incoming node's default definition overrides
436 // the original default definition, all children who relied on that
437 // definition must be updated accordingly.
438 Expected<xmlNsPtr> EC =
439 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
440 if (!EC) {
441 return EC.takeError();
442 }
443 xmlNsPtr ExplicitDefault = std::move(EC.get());
444 explicateNamespace(ExplicitDefault, NonDominantNode);
445 }
446 } else {
447 // The original did not define a default definition, however the new
448 // default definition still applies to all children, so they must be
449 // updated to explicitly refer to the namespace they had previously
450 // been inheriting implicitly.
451 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
452 Expected<xmlNsPtr> EC =
453 searchOrDefine(ClosestDefault->href, NonDominantNode);
454 if (!EC) {
455 return EC.takeError();
456 }
457 xmlNsPtr ExplicitDefault = std::move(EC.get());
458 explicateNamespace(ExplicitDefault, NonDominantNode);
459 }
460 }
461 }
462 if (NewDefinedDefaultHref) {
463 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
464 xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
465 OriginalNsDef->href = NewDefinedDefaultHref;
466 }
467 xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
468 return Error::success();
469}
470
471static bool isRecognizedNamespace(const unsigned char *NsHref) {
472 for (auto &Ns : MtNsHrefsPrefixes) {
473 if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data())reinterpret_cast<const unsigned char *>(Ns.first.data()
)
)) {
474 return true;
475 }
476 }
477 return false;
478}
479
480static bool hasRecognizedNamespace(xmlNodePtr Node) {
481 return isRecognizedNamespace(Node->ns->href);
482}
483
484// Ensure a node's inherited namespace is actually defined in the tree it
485// resides in.
486static Error reconcileNamespaces(xmlNodePtr Node) {
487 if (!Node) {
488 return Error::success();
489 }
490 if (hasInheritedNs(Node)) {
491 Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node);
492 if (!ExplicitOrError) {
493 return ExplicitOrError.takeError();
494 }
495 xmlNsPtr Explicit = std::move(ExplicitOrError.get());
496 Node->ns = Explicit;
497 }
498 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
499 if (auto E = reconcileNamespaces(Child)) {
500 return E;
501 }
502 }
503 return Error::success();
504}
505
506// Recursively merge the two given manifest trees, depending on which elements
507// are of a mergeable type, and choose namespaces according to which have
508// higher priority.
509static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
510 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
511 return E;
512 if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
513 return E;
514 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
515 xmlNode StoreNext;
516 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
517 xmlNodePtr OriginalChildWithName;
518 if (!isMergeableElement(Child->name) ||
519 !(OriginalChildWithName =
520 getChildWithName(OriginalRoot, Child->name)) ||
521 !hasRecognizedNamespace(Child)) {
522 StoreNext.next = Child->next;
523 xmlUnlinkNode(Child);
524 if (!xmlAddChild(OriginalRoot, Child)) {
525 return make_error<WindowsManifestError>(Twine("could not merge ") +
526 FROM_XML_CHAR(Child->name)reinterpret_cast<const char *>(Child->name));
527 }
528 if (auto E = reconcileNamespaces(Child)) {
529 return E;
530 }
531 Child = &StoreNext;
532 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
533 return E;
534 }
535 }
536 return Error::success();
537}
538
539static void stripComments(xmlNodePtr Root) {
540 xmlNode StoreNext;
541 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
542 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment")reinterpret_cast<const unsigned char *>("comment"))) {
543 stripComments(Child);
544 continue;
545 }
546 StoreNext.next = Child->next;
547 xmlNodePtr Remove = Child;
548 Child = &StoreNext;
549 xmlUnlinkNode(Remove);
550 xmlFreeNode(Remove);
551 }
552}
553
554// libxml2 assumes that attributes do not inherit default namespaces, whereas
555// the original mt.exe does make this assumption. This function reconciles
556// this by setting all attributes to have the inherited default namespace.
557static void setAttributeNamespaces(xmlNodePtr Node) {
558 for (xmlAttrPtr Attribute = Node->properties; Attribute;
559 Attribute = Attribute->next) {
560 if (!Attribute->ns) {
561 Attribute->ns = getClosestDefault(Node);
562 }
563 }
564 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
565 setAttributeNamespaces(Child);
566 }
567}
568
569// The merging process may create too many prefix defined namespaces. This
570// function removes all unnecessary ones from the tree.
571static void checkAndStripPrefixes(xmlNodePtr Node,
572 std::vector<xmlNsPtr> &RequiredPrefixes) {
573 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
7
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
11
Loop condition is true. Entering loop body
574 checkAndStripPrefixes(Child, RequiredPrefixes);
8
Calling 'checkAndStripPrefixes'
10
Calling 'checkAndStripPrefixes'
12
Calling 'checkAndStripPrefixes'
575 }
576 if (Node->ns && Node->ns->prefix != nullptr) {
13
Assuming field 'ns' is null
577 xmlNsPtr ClosestDefault = getClosestDefault(Node);
578 if (ClosestDefault &&
579 xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
580 Node->ns = ClosestDefault;
581 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
582 RequiredPrefixes.push_back(Node->ns);
583 }
584 }
585 for (xmlAttrPtr Attribute = Node->properties; Attribute;
14
Loop condition is false. Execution continues on line 597
586 Attribute = Attribute->next) {
587 if (Attribute->ns && Attribute->ns->prefix != nullptr) {
588 xmlNsPtr ClosestDefault = getClosestDefault(Node);
589 if (ClosestDefault &&
590 xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
591 Attribute->ns = ClosestDefault;
592 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
593 RequiredPrefixes.push_back(Attribute->ns);
594 }
595 }
596 }
597 xmlNsPtr Prev;
15
'Prev' declared without an initial value
598 xmlNs Temp;
599 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
600 if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
16
Assuming field 'prefix' is non-null
17
Taking false branch
601 Prev = Def;
602 continue;
603 }
604 if (Def == Node->nsDef) {
18
Assuming 'Def' is not equal to field 'nsDef'
19
Taking false branch
605 Node->nsDef = Def->next;
606 } else {
607 Prev->next = Def->next;
20
Access to field 'next' results in a dereference of an undefined pointer value (loaded from variable 'Prev')
608 }
609 Temp.next = Def->next;
610 xmlFreeNs(Def);
611 Def = &Temp;
612 }
613}
614
615WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
616 for (auto &Doc : MergedDocs)
617 xmlFreeDoc(Doc);
618}
619
620Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
621 MemoryBufferRef Manifest) {
622 if (Merged)
623 return make_error<WindowsManifestError>(
624 "merge after getMergedManifest is not supported");
625 if (Manifest.getBufferSize() == 0)
626 return make_error<WindowsManifestError>(
627 "attempted to merge empty manifest");
628 xmlSetGenericErrorFunc((void *)this,
629 WindowsManifestMergerImpl::errorCallback);
630 xmlDocPtr ManifestXML = xmlReadMemory(
631 Manifest.getBufferStart(), Manifest.getBufferSize(), "manifest.xml",
632 nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT);
633 xmlSetGenericErrorFunc(nullptr, nullptr);
634 if (auto E = getParseError())
635 return E;
636 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
637 stripComments(AdditionalRoot);
638 setAttributeNamespaces(AdditionalRoot);
639 if (CombinedDoc == nullptr) {
640 CombinedDoc = ManifestXML;
641 } else {
642 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
643 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
644 !isMergeableElement(AdditionalRoot->name) ||
645 !hasRecognizedNamespace(AdditionalRoot)) {
646 return make_error<WindowsManifestError>("multiple root nodes");
647 }
648 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
649 return E;
650 }
651 }
652 MergedDocs.push_back(ManifestXML);
653 return Error::success();
654}
655
656std::unique_ptr<MemoryBuffer>
657WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
658 if (!Merged) {
2
Assuming field 'Merged' is false
3
Taking true branch
659 Merged = true;
660
661 if (!CombinedDoc)
4
Assuming field 'CombinedDoc' is non-null
5
Taking false branch
662 return nullptr;
663
664 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
665 std::vector<xmlNsPtr> RequiredPrefixes;
666 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
6
Calling 'checkAndStripPrefixes'
667 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
668 xmlNewDoc((const unsigned char *)"1.0"));
669 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
670 assert(nullptr == xmlDocGetRootElement(CombinedDoc))(static_cast <bool> (nullptr == xmlDocGetRootElement(CombinedDoc
)) ? void (0) : __assert_fail ("nullptr == xmlDocGetRootElement(CombinedDoc)"
, "llvm/lib/WindowsManifest/WindowsManifestMerger.cpp", 670, __extension__
__PRETTY_FUNCTION__))
;
671
672 xmlKeepBlanksDefault(0);
673 xmlChar *Buff = nullptr;
674 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1);
675 Buffer.reset(Buff);
676 }
677
678 return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef(
679 FROM_XML_CHAR(Buffer.get())reinterpret_cast<const char *>(Buffer.get()), (size_t)BufferSize))
680 : nullptr;
681}
682
683bool windows_manifest::isAvailable() { return true; }
684
685#else
686
687WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
688}
689
690Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
691 MemoryBufferRef Manifest) {
692 return make_error<WindowsManifestError>("no libxml2");
693}
694
695std::unique_ptr<MemoryBuffer>
696WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
697 return nullptr;
698}
699
700bool windows_manifest::isAvailable() { return false; }
701
702#endif
703
704WindowsManifestMerger::WindowsManifestMerger()
705 : Impl(std::make_unique<WindowsManifestMergerImpl>()) {}
706
707WindowsManifestMerger::~WindowsManifestMerger() = default;
708
709Error WindowsManifestMerger::merge(MemoryBufferRef Manifest) {
710 return Impl->merge(Manifest);
711}
712
713std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
714 return Impl->getMergedManifest();
1
Calling 'WindowsManifestMergerImpl::getMergedManifest'
715}
716
717void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
718 void *Ctx, const char *Format, ...) {
719 auto *Merger = (WindowsManifestMergerImpl *)Ctx;
720 Merger->ParseErrorOccurred = true;
721}
722
723Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
724 if (!ParseErrorOccurred)
725 return Error::success();
726 return make_error<WindowsManifestError>("invalid xml document");
727}