From f27a090911e31aeab239bafaf420665cb04698fa Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 26 Jan 2026 14:17:04 -0500 Subject: [PATCH] GP-6371 - Gnu Demangler - Fixed failure to parse a global guard variable --- .../demangler/gnu/GnuDemanglerParser.java | 15 ++++++++++++-- .../demangler/GnuDemanglerParserTest.java | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java index 63798aef8a..8892cca63c 100644 --- a/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java +++ b/Ghidra/Features/GnuDemangler/src/main/java/ghidra/app/util/demangler/gnu/GnuDemanglerParser.java @@ -665,8 +665,8 @@ public class GnuDemanglerParser { int pos = itemText.lastIndexOf(Namespace.DELIMITER); if (pos == -1) { - throw new DemanglerParseException( - "Expected the demangled string to contain a namespace"); + // We now allow this case instead of throwing an exception + return null; } String parentText = itemText.substring(0, pos); @@ -1715,6 +1715,12 @@ public class GnuDemanglerParser { } + /* + Note: this class is used to handle things like 'guard variable for' or other items that + don't parse directly as functions or variables. Historically these items have always been + in a parent non-global namespace. Global variables do not have a parent namespace as part + of their name. We have changed this class to allow the case of no specified namespace. + */ private class ItemInNamespaceHandler extends SpecialPrefixHandler { ItemInNamespaceHandler(String demangled) { @@ -1728,6 +1734,11 @@ public class GnuDemanglerParser { @Override DemangledObject doBuild(Demangled namespace) { DemangledObject demangledObject = parseItemInNamespace(type); + if (demangledObject == null) { + // The item we are demangling is global and not in a namespace. Assume the item + // passed in is the valid demangled object. + return (DemangledObject) namespace; + } return demangledObject; } } diff --git a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java index 8a56e2bb84..e16b87da2b 100644 --- a/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java +++ b/Ghidra/Features/GnuDemangler/src/test/java/ghidra/app/util/demangler/GnuDemanglerParserTest.java @@ -672,6 +672,26 @@ public class GnuDemanglerParserTest extends AbstractGenericTest { assertNull(variable.getDataType()); // no type information provided } + @Test + public void testGuardVariable_GlobalVariable() throws Exception { + + String mangled = "_ZGV17globalVariableFoo"; + + String demangled = process.demangle(mangled); + + assertEquals("guard variable for globalVariableFoo", demangled); + + DemangledObject object = parser.parse(mangled, demangled); + assertType(object, DemangledVariable.class); + assertName(object, "globalVariableFoo"); + + assertEquals("globalVariableFoo", object.getSignature(false)); + + DemangledVariable variable = (DemangledVariable) object; + assertEquals("globalVariableFoo", variable.getName()); + assertNull(variable.getDataType()); // no type information provided + } + @Test public void testConstFunction() throws Exception { //