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 (A || B)

69 return A == B;

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 && Attribute->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 (Def->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.