Skip to content

Commit f792f14

Browse files
authored
[WebAssembly] Allocate MCSymbolWasm data on MCContext (#85866)
Fixes #85578, a use-after-free caused by some `MCSymbolWasm` data being freed too early. Previously, `WebAssemblyAsmParser` owned the data that is moved to `MCContext` by this PR, which caused problems when handling module ASM, because the ASM parser was destroyed after parsing the module ASM, but the symbols persisted. The added test passes locally with an LLVM build with AddressSanitizer enabled. Implementation notes: * I've called the added method <code>allocate<b><i>Generic</i></b>String</code> and added the second paragraph of its documentation to maybe guide people a bit on when to use this method (based on my (limited) understanding of the `MCContext` class). We could also just call it `allocateString` and remove that second paragraph. * The added `createWasmSignature` method does not support taking the return and parameter types as arguments: Specifying them afterwards is barely any longer and prevents them from being accidentally specified in the wrong order. * This removes a _"TODO: Do the uniquing of Signatures here instead of ObjectFileWriter?"_ since the field it's attached to is also removed. Let me know if you think that TODO should be preserved somewhere.
1 parent 9c9f940 commit f792f14

File tree

9 files changed

+86
-74
lines changed

9 files changed

+86
-74
lines changed

llvm/include/llvm/MC/MCContext.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/Support/Compiler.h"
2727
#include "llvm/Support/Error.h"
2828
#include "llvm/Support/MD5.h"
29+
#include "llvm/Support/StringSaver.h"
2930
#include "llvm/Support/raw_ostream.h"
3031
#include <algorithm>
3132
#include <cassert>
@@ -70,6 +71,10 @@ class SMLoc;
7071
class SourceMgr;
7172
enum class EmitDwarfUnwindType;
7273

74+
namespace wasm {
75+
struct WasmSignature;
76+
}
77+
7378
/// Context object for machine code objects. This class owns all of the
7479
/// sections that it creates.
7580
///
@@ -139,6 +144,8 @@ class MCContext {
139144
SpecificBumpPtrAllocator<MCSectionXCOFF> XCOFFAllocator;
140145
SpecificBumpPtrAllocator<MCInst> MCInstAllocator;
141146

147+
SpecificBumpPtrAllocator<wasm::WasmSignature> WasmSignatureAllocator;
148+
142149
/// Bindings of names to symbols.
143150
SymbolTable Symbols;
144151

@@ -538,6 +545,10 @@ class MCContext {
538545
/// inline assembly.
539546
void registerInlineAsmLabel(MCSymbol *Sym);
540547

548+
/// Allocates and returns a new `WasmSignature` instance (with empty parameter
549+
/// and return type lists).
550+
wasm::WasmSignature *createWasmSignature();
551+
541552
/// @}
542553

543554
/// \name Section Management
@@ -850,6 +861,12 @@ class MCContext {
850861

851862
void deallocate(void *Ptr) {}
852863

864+
/// Allocates a copy of the given string on the allocator managed by this
865+
/// context and returns the result.
866+
StringRef allocateString(StringRef s) {
867+
return StringSaver(Allocator).save(s);
868+
}
869+
853870
bool hadError() { return HadError; }
854871
void diagnose(const SMDiagnostic &SMD);
855872
void reportError(SMLoc L, const Twine &Msg);

llvm/lib/MC/MCContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ void MCContext::reset() {
147147
XCOFFAllocator.DestroyAll();
148148
MCInstAllocator.DestroyAll();
149149
SPIRVAllocator.DestroyAll();
150+
WasmSignatureAllocator.DestroyAll();
150151

151152
MCSubtargetAllocator.DestroyAll();
152153
InlineAsmUsedLabelNames.clear();
@@ -375,6 +376,10 @@ void MCContext::registerInlineAsmLabel(MCSymbol *Sym) {
375376
InlineAsmUsedLabelNames[Sym->getName()] = Sym;
376377
}
377378

379+
wasm::WasmSignature *MCContext::createWasmSignature() {
380+
return new (WasmSignatureAllocator.Allocate()) wasm::WasmSignature;
381+
}
382+
378383
MCSymbolXCOFF *
379384
MCContext::createXCOFFSymbolImpl(const StringMapEntry<bool> *Name,
380385
bool IsTemporary) {

llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
196196
MCAsmParser &Parser;
197197
MCAsmLexer &Lexer;
198198

199-
// Much like WebAssemblyAsmPrinter in the backend, we have to own these.
200-
std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
201-
std::vector<std::unique_ptr<std::string>> Names;
202-
203199
// Order of labels, directives and instructions in a .s file have no
204200
// syntactical enforcement. This class is a callback from the actual parser,
205201
// and yet we have to be feeding data to the streamer in a very particular
@@ -287,16 +283,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
287283
return Parser.Error(Loc.isValid() ? Loc : Lexer.getTok().getLoc(), Msg);
288284
}
289285

290-
void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
291-
Signatures.push_back(std::move(Sig));
292-
}
293-
294-
StringRef storeName(StringRef Name) {
295-
std::unique_ptr<std::string> N = std::make_unique<std::string>(Name);
296-
Names.push_back(std::move(N));
297-
return *Names.back();
298-
}
299-
300286
std::pair<StringRef, StringRef> nestingString(NestingType NT) {
301287
switch (NT) {
302288
case Function:
@@ -640,21 +626,20 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
640626
// represent as a signature, such that we can re-build this signature,
641627
// attach it to an anonymous symbol, which is what WasmObjectWriter
642628
// expects to be able to recreate the actual unique-ified type indices.
629+
auto &Ctx = getContext();
643630
auto Loc = Parser.getTok();
644-
auto Signature = std::make_unique<wasm::WasmSignature>();
645-
if (parseSignature(Signature.get()))
631+
auto Signature = Ctx.createWasmSignature();
632+
if (parseSignature(Signature))
646633
return true;
647634
// Got signature as block type, don't need more
648-
TC.setLastSig(*Signature.get());
635+
TC.setLastSig(*Signature);
649636
if (ExpectBlockType)
650-
NestingStack.back().Sig = *Signature.get();
637+
NestingStack.back().Sig = *Signature;
651638
ExpectBlockType = false;
652-
auto &Ctx = getContext();
653639
// The "true" here will cause this to be a nameless symbol.
654640
MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
655641
auto *WasmSym = cast<MCSymbolWasm>(Sym);
656-
WasmSym->setSignature(Signature.get());
657-
addSignature(std::move(Signature));
642+
WasmSym->setSignature(Signature);
658643
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
659644
const MCExpr *Expr = MCSymbolRefExpr::create(
660645
WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
@@ -887,12 +872,11 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
887872
CurrentState = FunctionStart;
888873
LastFunctionLabel = WasmSym;
889874
}
890-
auto Signature = std::make_unique<wasm::WasmSignature>();
891-
if (parseSignature(Signature.get()))
875+
auto Signature = Ctx.createWasmSignature();
876+
if (parseSignature(Signature))
892877
return ParseStatus::Failure;
893878
TC.funcDecl(*Signature);
894-
WasmSym->setSignature(Signature.get());
895-
addSignature(std::move(Signature));
879+
WasmSym->setSignature(Signature);
896880
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
897881
TOut.emitFunctionType(WasmSym);
898882
// TODO: backend also calls TOut.emitIndIdx, but that is not implemented.
@@ -909,7 +893,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
909893
if (ExportName.empty())
910894
return ParseStatus::Failure;
911895
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
912-
WasmSym->setExportName(storeName(ExportName));
896+
WasmSym->setExportName(Ctx.allocateString(ExportName));
913897
TOut.emitExportName(WasmSym, ExportName);
914898
return expect(AsmToken::EndOfStatement, "EOL");
915899
}
@@ -924,7 +908,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
924908
if (ImportModule.empty())
925909
return ParseStatus::Failure;
926910
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
927-
WasmSym->setImportModule(storeName(ImportModule));
911+
WasmSym->setImportModule(Ctx.allocateString(ImportModule));
928912
TOut.emitImportModule(WasmSym, ImportModule);
929913
return expect(AsmToken::EndOfStatement, "EOL");
930914
}
@@ -939,7 +923,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
939923
if (ImportName.empty())
940924
return ParseStatus::Failure;
941925
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
942-
WasmSym->setImportName(storeName(ImportName));
926+
WasmSym->setImportName(Ctx.allocateString(ImportName));
943927
TOut.emitImportName(WasmSym, ImportName);
944928
return expect(AsmToken::EndOfStatement, "EOL");
945929
}
@@ -949,11 +933,10 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
949933
if (SymName.empty())
950934
return ParseStatus::Failure;
951935
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
952-
auto Signature = std::make_unique<wasm::WasmSignature>();
936+
auto Signature = Ctx.createWasmSignature();
953937
if (parseRegTypeList(Signature->Params))
954938
return ParseStatus::Failure;
955-
WasmSym->setSignature(Signature.get());
956-
addSignature(std::move(Signature));
939+
WasmSym->setSignature(Signature);
957940
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
958941
TOut.emitTagType(WasmSym);
959942
// TODO: backend also calls TOut.emitIndIdx, but that is not implemented.

llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,10 @@ MCSymbol *WebAssemblyAsmPrinter::getOrCreateWasmSymbol(StringRef Name) {
266266
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
267267
WebAssembly::getLibcallSignature(Subtarget, Name, Returns, Params);
268268
}
269-
auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
270-
std::move(Params));
271-
WasmSym->setSignature(Signature.get());
272-
addSignature(std::move(Signature));
269+
auto Signature = OutContext.createWasmSignature();
270+
Signature->Returns = std::move(Returns);
271+
Signature->Params = std::move(Params);
272+
WasmSym->setSignature(Signature);
273273

274274
return WasmSym;
275275
}
@@ -338,11 +338,11 @@ void WebAssemblyAsmPrinter::emitDecls(const Module &M) {
338338
// and thus also contain a signature, but we need to get the signature
339339
// anyway here in case it is an invoke that has not yet been created. We
340340
// will discard it later if it turns out not to be necessary.
341-
auto Signature = signatureFromMVTs(Results, Params);
341+
auto Signature = signatureFromMVTs(OutContext, Results, Params);
342342
bool InvokeDetected = false;
343343
auto *Sym = getMCSymbolForFunction(
344344
&F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
345-
Signature.get(), InvokeDetected);
345+
Signature, InvokeDetected);
346346

347347
// Multiple functions can be mapped to the same invoke symbol. For
348348
// example, two IR functions '__invoke_void_i8*' and '__invoke_void_i32'
@@ -353,19 +353,15 @@ void WebAssemblyAsmPrinter::emitDecls(const Module &M) {
353353

354354
Sym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
355355
if (!Sym->getSignature()) {
356-
Sym->setSignature(Signature.get());
357-
addSignature(std::move(Signature));
358-
} else {
359-
// This symbol has already been created and had a signature. Discard it.
360-
Signature.reset();
356+
Sym->setSignature(Signature);
361357
}
362358

363359
getTargetStreamer()->emitFunctionType(Sym);
364360

365361
if (F.hasFnAttribute("wasm-import-module")) {
366362
StringRef Name =
367363
F.getFnAttribute("wasm-import-module").getValueAsString();
368-
Sym->setImportModule(storeName(Name));
364+
Sym->setImportModule(OutContext.allocateString(Name));
369365
getTargetStreamer()->emitImportModule(Sym, Name);
370366
}
371367
if (F.hasFnAttribute("wasm-import-name")) {
@@ -375,14 +371,14 @@ void WebAssemblyAsmPrinter::emitDecls(const Module &M) {
375371
InvokeDetected
376372
? Sym->getName()
377373
: F.getFnAttribute("wasm-import-name").getValueAsString();
378-
Sym->setImportName(storeName(Name));
374+
Sym->setImportName(OutContext.allocateString(Name));
379375
getTargetStreamer()->emitImportName(Sym, Name);
380376
}
381377

382378
if (F.hasFnAttribute("wasm-export-name")) {
383379
auto *Sym = cast<MCSymbolWasm>(getSymbol(&F));
384380
StringRef Name = F.getFnAttribute("wasm-export-name").getValueAsString();
385-
Sym->setExportName(storeName(Name));
381+
Sym->setExportName(OutContext.allocateString(Name));
386382
getTargetStreamer()->emitExportName(Sym, Name);
387383
}
388384
}
@@ -618,10 +614,9 @@ void WebAssemblyAsmPrinter::emitFunctionBodyStart() {
618614
SmallVector<MVT, 4> ParamVTs;
619615
computeSignatureVTs(F.getFunctionType(), &F, F, TM, ParamVTs, ResultVTs);
620616

621-
auto Signature = signatureFromMVTs(ResultVTs, ParamVTs);
617+
auto Signature = signatureFromMVTs(OutContext, ResultVTs, ParamVTs);
622618
auto *WasmSym = cast<MCSymbolWasm>(CurrentFnSym);
623-
WasmSym->setSignature(Signature.get());
624-
addSignature(std::move(Signature));
619+
WasmSym->setSignature(Signature);
625620
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
626621

627622
getTargetStreamer()->emitFunctionType(WasmSym);

llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyAsmPrinter final : public AsmPrinter {
2222
const WebAssemblySubtarget *Subtarget;
2323
const MachineRegisterInfo *MRI;
2424
WebAssemblyFunctionInfo *MFI;
25-
// TODO: Do the uniquing of Signatures here instead of ObjectFileWriter?
26-
std::vector<std::unique_ptr<wasm::WasmSignature>> Signatures;
27-
std::vector<std::unique_ptr<std::string>> Names;
2825
bool signaturesEmitted = false;
2926

30-
StringRef storeName(StringRef Name) {
31-
std::unique_ptr<std::string> N = std::make_unique<std::string>(Name);
32-
Names.push_back(std::move(N));
33-
return *Names.back();
34-
}
35-
3627
public:
3728
explicit WebAssemblyAsmPrinter(TargetMachine &TM,
3829
std::unique_ptr<MCStreamer> Streamer)
@@ -44,9 +35,6 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyAsmPrinter final : public AsmPrinter {
4435
}
4536

4637
const WebAssemblySubtarget &getSubtarget() const { return *Subtarget; }
47-
void addSignature(std::unique_ptr<wasm::WasmSignature> &&Sig) {
48-
Signatures.push_back(std::move(Sig));
49-
}
5038

5139
//===------------------------------------------------------------------===//
5240
// MachineFunctionPass Implementation.

llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,13 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
7373
SmallVector<MVT, 4> ParamMVTs;
7474
const auto *const F = dyn_cast<Function>(Global);
7575
computeSignatureVTs(FuncTy, F, CurrentFunc, TM, ParamMVTs, ResultMVTs);
76-
auto Signature = signatureFromMVTs(ResultMVTs, ParamMVTs);
76+
auto Signature = signatureFromMVTs(Ctx, ResultMVTs, ParamMVTs);
7777

7878
bool InvokeDetected = false;
7979
auto *WasmSym = Printer.getMCSymbolForFunction(
8080
F, WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj,
81-
Signature.get(), InvokeDetected);
82-
WasmSym->setSignature(Signature.get());
83-
Printer.addSignature(std::move(Signature));
81+
Signature, InvokeDetected);
82+
WasmSym->setSignature(Signature);
8483
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
8584
return WasmSym;
8685
}
@@ -142,12 +141,12 @@ MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
142141
MCOperand WebAssemblyMCInstLower::lowerTypeIndexOperand(
143142
SmallVectorImpl<wasm::ValType> &&Returns,
144143
SmallVectorImpl<wasm::ValType> &&Params) const {
145-
auto Signature = std::make_unique<wasm::WasmSignature>(std::move(Returns),
146-
std::move(Params));
144+
auto Signature = Ctx.createWasmSignature();
145+
Signature->Returns = std::move(Returns);
146+
Signature->Params = std::move(Params);
147147
MCSymbol *Sym = Printer.createTempSymbol("typeindex");
148148
auto *WasmSym = cast<MCSymbolWasm>(Sym);
149-
WasmSym->setSignature(Signature.get());
150-
Printer.addSignature(std::move(Signature));
149+
WasmSym->setSignature(Signature);
151150
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
152151
const MCExpr *Expr =
153152
MCSymbolRefExpr::create(WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);

llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ void llvm::valTypesFromMVTs(ArrayRef<MVT> In,
111111
Out.push_back(WebAssembly::toValType(Ty));
112112
}
113113

114-
std::unique_ptr<wasm::WasmSignature>
115-
llvm::signatureFromMVTs(const SmallVectorImpl<MVT> &Results,
114+
wasm::WasmSignature *
115+
llvm::signatureFromMVTs(MCContext &Ctx, const SmallVectorImpl<MVT> &Results,
116116
const SmallVectorImpl<MVT> &Params) {
117-
auto Sig = std::make_unique<wasm::WasmSignature>();
117+
auto Sig = Ctx.createWasmSignature();
118118
valTypesFromMVTs(Results, Sig->Returns);
119119
valTypesFromMVTs(Params, Sig->Params);
120120
return Sig;

llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ void computeSignatureVTs(const FunctionType *Ty, const Function *TargetFunc,
171171

172172
void valTypesFromMVTs(ArrayRef<MVT> In, SmallVectorImpl<wasm::ValType> &Out);
173173

174-
std::unique_ptr<wasm::WasmSignature>
175-
signatureFromMVTs(const SmallVectorImpl<MVT> &Results,
176-
const SmallVectorImpl<MVT> &Params);
174+
wasm::WasmSignature *signatureFromMVTs(MCContext &Ctx,
175+
const SmallVectorImpl<MVT> &Results,
176+
const SmallVectorImpl<MVT> &Params);
177177

178178
namespace yaml {
179179

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; Ensure that symbols from module ASM are properly exported.
2+
;
3+
; Regression test for https://github.com/llvm/llvm-project/issues/85578.
4+
5+
; RUN: llc -mtriple=wasm32-unknown-unknown -filetype=obj %s -o - | obj2yaml | FileCheck %s
6+
7+
module asm "test_func:"
8+
module asm " .globl test_func"
9+
module asm " .functype test_func (i32) -> (i32)"
10+
module asm " .export_name test_func, test_export"
11+
module asm " end_function"
12+
13+
; CHECK: - Type: TYPE
14+
; CHECK-NEXT: Signatures:
15+
; CHECK-NEXT: - Index: 0
16+
; CHECK-NEXT: ParamTypes:
17+
; CHECK-NEXT: - I32
18+
; CHECK-NEXT: ReturnTypes:
19+
; CHECK-NEXT: - I32
20+
21+
; CHECK: - Type: EXPORT
22+
; CHECK-NEXT: Exports:
23+
; CHECK-NEXT: - Name: test_export
24+
; CHECK-NEXT: Kind: FUNCTION
25+
; CHECK-NEXT: Index: 0

0 commit comments

Comments
 (0)