-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[llvm-objdump] Fix memory leak in mcpuHelp()
#172594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-llvm-binary-utilities Author: Ruoyu Qiu (cabbaken) ChangesThis patch fix memory leak introduced in #165661 Full diff: https://github.com/llvm/llvm-project/pull/172594.diff 4 Files Affected:
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 4406a9d45c97e..503cf641a221f 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -246,6 +246,9 @@ Changes to the LLVM tools
emitted on stdout, to account for spaces or other special characters in path.
(`#97305 <https://github.com/llvm/llvm-project/pull/97305>`_).
+* `llvm-objdump` now supports using `--mcpu=help` and `--mattr=help` with the `--triple` option
+ without requiring an input file or the `-d` (disassemble) flag.
+
Changes to LLDB
---------------------------------
diff --git a/llvm/test/tools/llvm-objdump/mattr-mcpu-help.test b/llvm/test/tools/llvm-objdump/mattr-mcpu-help.test
index 65c426008fd6a..7aeaf66bab1ee 100644
--- a/llvm/test/tools/llvm-objdump/mattr-mcpu-help.test
+++ b/llvm/test/tools/llvm-objdump/mattr-mcpu-help.test
@@ -1,12 +1,40 @@
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-objdump -d %t --mattr=help 2>&1 | FileCheck %s
-# RUN: llvm-objdump -d %t --mcpu=help 2>&1 | FileCheck %s
# REQUIRES: x86-registered-target
+# RUN: yaml2obj --docnum=1 %s -o %t
+# RUN: llvm-objdump -d %t --mattr=help 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-DISASSEMBLE
+# RUN: llvm-objdump -d %t --mcpu=help 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-DISASSEMBLE
+
# CHECK: Available CPUs for this target:
# CHECK: Available features for this target:
## To check we still disassemble the file:
-# CHECK: file format elf64-x86-64
+# CHECK-DISASSEMBLE: file format elf64-x86-64
+
+## The help message can be printed without -d.
+# RUN: llvm-objdump --mattr=help %t 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DISASSEMBLE
+# RUN: llvm-objdump --mcpu=help %t 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DISASSEMBLE
+
+# CHECK-NO-DISASSEMBLE-NOT: file format elf64-x86-64
+
+## We still handle other options.
+# RUN: llvm-objdump --mattr=help --section-headers %t 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-SECTION-HEADERS
+# RUN: llvm-objdump --mcpu=help --section-headers %t 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-SECTION-HEADERS
+
+# CHECK-SECTION-HEADERS: Sections:
+# CHECK-SECTION-HEADERS: Idx Name Size VMA Type
+
+## We report an error when we can't infer the triple because we don't have --triple or an input object (including a.out).
+# RUN: not llvm-objdump --mattr=help 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-MISSING-ERROR --implicit-check-not=error: -DMSG=%errc_ENOENT
+# RUN: not llvm-objdump --mcpu=help 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-MISSING-ERROR --implicit-check-not=error: -DMSG=%errc_ENOENT
+
+# CHECK-MISSING-ERROR: llvm-objdump{{.*}}: error: 'a.out': triple was not specified and could not be inferred from the input file: [[MSG]]
--- !ELF
FileHeader:
@@ -14,3 +42,68 @@ FileHeader:
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
+
+# RUN: yaml2obj --docnum=2 %s -o %t.minidump
+## We report an error when the binary file isn't an object file format.
+# RUN: not llvm-objdump --mattr=help %t.minidump 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-UNSUPPORTED-ERROR --implicit-check-not=error: -DFILE=%t.minidump
+# RUN: not llvm-objdump --mcpu=help %t.minidump 2>&1 \
+# RUN: | FileCheck %s --check-prefix=CHECK-UNSUPPORTED-ERROR --implicit-check-not=error: -DFILE=%t.minidump
+
+# CHECK-UNSUPPORTED-ERROR: llvm-objdump{{.*}}: error: '[[FILE]]': target triple could not be derived from input file
+
+--- !minidump
+Streams:
+ - Type: SystemInfo
+ Processor Arch: PPC
+ Platform ID: Linux
+
+# RUN: llvm-ar rc %t.a %t
+# RUN: llvm-objdump --mcpu=help %t.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK
+# RUN: llvm-objdump --mattr=help %t.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK
+
+## We report an error when the triple cannot be inferred from any archive member.
+# RUN: llvm-ar rc %t.empty.a
+# RUN: not llvm-objdump --mcpu=help %t.empty.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK-UNSUPPORTED-ERROR --implicit-check-not=error: -DFILE=%t.empty.a
+# RUN: not llvm-objdump --mattr=help %t.empty.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK-UNSUPPORTED-ERROR --implicit-check-not=error: -DFILE=%t.empty.a
+
+## We are able to handle an archive with unsupported binary files. The target is
+## derived from the first recognised object file.
+# RUN: llvm-ar rc %t.a %t.minidump %t
+# RUN: llvm-objdump --mcpu=help %t.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK
+# RUN: llvm-objdump --mattr=help %t.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK
+
+## We report an error when the archive is malformed.
+# RUN: yaml2obj --docnum=3 %s -o %t.malformed.archive.a
+# RUN: not llvm-objdump --mcpu=help %t.malformed.archive.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK-MALFORMED-ARCHIVE-ERROR --implicit-check-not=error: -DFILE=%t.malformed.archive.a
+# RUN: not llvm-objdump --mattr=help %t.malformed.archive.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK-MALFORMED-ARCHIVE-ERROR --implicit-check-not=error: -DFILE=%t.malformed.archive.a
+
+# CHECK-MALFORMED-ARCHIVE-ERROR: llvm-objdump{{.*}}: error: '[[FILE]]': truncated or malformed archive
+
+--- !Arch
+Members:
+ - Name: 'foo.c'
+ Size: '1'
+
+## We report an error when we encounter an unexpected error while iterating files in an archive.
+# RUN: yaml2obj --docnum=4 %s -o %t.invalid.error.code.archive.a
+# RUN: not llvm-objdump --mcpu=help %t.invalid.error.code.archive.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK-INVALID-ERROR-ARCHIVE-ERROR --implicit-check-not=error: -DFILE=%t.invalid.error.code.archive.a
+# RUN: not llvm-objdump --mattr=help %t.invalid.error.code.archive.a 2>&1 \
+# RUN: | FileCheck %s --check-prefixes=CHECK-INVALID-ERROR-ARCHIVE-ERROR --implicit-check-not=error: -DFILE=%t.invalid.error.code.archive.a
+
+# CHECK-INVALID-ERROR-ARCHIVE-ERROR: llvm-objdump{{.*}}: error: [[FILE]](<file index: 1>): truncated or malformed archive (long name offset characters after the '/' are not all decimal numbers: '&a25*' for archive member header at offset 68)
+
+--- !Arch
+Members:
+## We need the first member to be a valid member to trigger the right error.
+ - Name: 'hello.c/'
+ - Name: "/&a25*"
diff --git a/llvm/test/tools/llvm-objdump/mattr-mcpu-triple-help.test b/llvm/test/tools/llvm-objdump/mattr-mcpu-triple-help.test
new file mode 100644
index 0000000000000..1212773afc35a
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/mattr-mcpu-triple-help.test
@@ -0,0 +1,21 @@
+# RUN: yaml2obj %s -o %t
+# REQUIRES: x86-registered-target
+
+## When specifying --triple, the help message should be printed for the specified target.
+# RUN: llvm-objdump --mattr=help --triple=x86_64 2>&1 | FileCheck %s
+# RUN: llvm-objdump --mcpu=help --triple=x86_64 2>&1 | FileCheck %s
+
+## The help message will depend on the target specified by --triple even if the input is for a different target.
+# RUN: llvm-objdump --mattr=help --triple=x86_64 %t 2>&1 | FileCheck %s
+# RUN: llvm-objdump --mcpu=help --triple=x86_64 %t 2>&1 | FileCheck %s
+
+# CHECK: Available CPUs for this target:
+# CHECK: x86-64
+# CHECK: Available features for this target:
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_MIPS
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 38c3f31441c06..5e816f054e74b 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -3533,6 +3533,58 @@ commaSeparatedValues(const llvm::opt::InputArgList &InputArgs, int ID) {
return Values;
}
+static void mcpuHelp() {
+ Triple TheTriple;
+
+ if (!TripleName.empty()) {
+ TheTriple.setTriple(TripleName);
+ } else {
+ assert(!InputFilenames.empty());
+ Expected<OwningBinary<Binary>> OBinary = createBinary(InputFilenames[0]);
+ if (Error E = OBinary.takeError()) {
+ reportError(InputFilenames[0], "triple was not specified and could not "
+ "be inferred from the input file: " +
+ toString(std::move(E)));
+ }
+
+ Binary *Bin = OBinary->getBinary();
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin)) {
+ TheTriple = Obj->makeTriple();
+ } else if (Archive *A = dyn_cast<Archive>(Bin)) {
+ Error Err = Error::success();
+ unsigned I = -1;
+ for (auto &C : A->children(Err)) {
+ ++I;
+ Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
+ if (!ChildOrErr) {
+ if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
+ reportError(std::move(E), getFileNameForError(C, I),
+ A->getFileName());
+ continue;
+ }
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
+ TheTriple = Obj->makeTriple();
+ break;
+ }
+ }
+ if (Err)
+ reportError(std::move(Err), A->getFileName());
+ }
+ if (TheTriple.empty())
+ reportError(InputFilenames[0],
+ "target triple could not be derived from input file");
+ }
+
+ std::string ErrMessage;
+ const Target *DummyTarget =
+ TargetRegistry::lookupTarget(TheTriple, ErrMessage);
+ if (!DummyTarget)
+ reportCmdLineError(ErrMessage);
+ // We need to access the Help() through the corresponding MCSubtargetInfo.
+ std::unique_ptr<MCSubtargetInfo> MSI(
+ DummyTarget->createMCSubtargetInfo(TheTriple, "help", ""));
+}
+
static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) {
MachOOpt = true;
FullLeadingAddr = true;
@@ -3826,20 +3878,31 @@ int llvm_objdump_main(int argc, char **argv, const llvm::ToolContext &) {
!DisassembleSymbols.empty())
Disassemble = true;
- if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null &&
- !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
- !Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
- !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&
- !(MachOOpt &&
- (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||
- DylibsUsed || ExportsTrie || FirstPrivateHeader ||
- FunctionStartsType != FunctionStartsMode::None || IndirectSymbols ||
- InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase ||
- Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()))) {
+ const bool PrintCpuHelp = (MCPU == "help" || is_contained(MAttrs, "help"));
+
+ const bool ShouldDump =
+ ArchiveHeaders || Disassemble || DwarfDumpType != DIDT_Null ||
+ DynamicRelocations || FileHeaders || PrivateHeaders || RawClangAST ||
+ Relocations || SectionHeaders || SectionContents || SymbolTable ||
+ DynamicSymbolTable || UnwindInfo || FaultMapSection || Offloading ||
+ (MachOOpt &&
+ (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||
+ DylibsUsed || ExportsTrie || FirstPrivateHeader ||
+ FunctionStartsType != FunctionStartsMode::None || IndirectSymbols ||
+ InfoPlist || LazyBind || LinkOptHints || ObjcMetaData || Rebase ||
+ Rpaths || UniversalHeaders || WeakBind || !FilterSections.empty()));
+
+ if (!ShouldDump && !PrintCpuHelp) {
T->printHelp(ToolName);
return 2;
}
+ if (PrintCpuHelp) {
+ mcpuHelp();
+ if (!ShouldDump)
+ return EXIT_SUCCESS;
+ }
+
DisasmSymbolSet.insert_range(DisassembleSymbols);
llvm::for_each(InputFilenames, dumpInput);
|
|
@jh7370 diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 97032ec..5e816f0 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -3581,7 +3581,8 @@ static void mcpuHelp() {
if (!DummyTarget)
reportCmdLineError(ErrMessage);
// We need to access the Help() through the corresponding MCSubtargetInfo.
- DummyTarget->createMCSubtargetInfo(TheTriple, "help", "");
+ std::unique_ptr<MCSubtargetInfo> MSI(
+ DummyTarget->createMCSubtargetInfo(TheTriple, "help", ""));
}
static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine to me, with one addition.
| TargetRegistry::lookupTarget(TheTriple, ErrMessage); | ||
| if (!DummyTarget) | ||
| reportCmdLineError(ErrMessage); | ||
| // We need to access the Help() through the corresponding MCSubtargetInfo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expand this comment to mention why you are wrapping the result in a unique_ptr, e.g. "To avoid a memory leak, we wrap the createMcSubtargetInfo result in a unique_ptr."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your reply! I added comment in the latest commit.
This patch fix memory leak introduced in #165661.
The call to
DummyTarget->createMCSubtargetInfowithinmcpuHelp()returns a pointer that is not subsequently freed, leading to a memory leak.Use
std::unique_ptrto ensure the memory is released automatically.