From 5259f4b7ae2aa4d7aaf44511057fc66fa56d09d4 Mon Sep 17 00:00:00 2001 From: vigneshakaviki Date: Sat, 4 Apr 2026 18:43:08 -0700 Subject: [PATCH] GP-0: Fix VarargsFilter doing nothing due to firstVarArgSlot never being set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the Function Editor assigns parameter storage, PrototypePieces.firstVarArgSlot was always left at -1, causing VarargsFilter.filter() to unconditionally return false. Any .cspec rule using (e.g. MSP430's goto_stack for the last fixed arg) had no effect when storage was (re-)assigned via the UI. Fix: add a getStorageLocations overload that accepts an isVarArgs flag. When true, firstVarArgSlot is set to proto.intypes.size() — meaning all supplied parameters are non-optional and the first vararg slot follows immediately after the last one. FunctionData.updateParameterAndReturnStorage() now passes hasVarArgs to this overload, so VarargsFilter-based rules fire correctly. Fixes #9091 Co-Authored-By: Claude Sonnet 4.6 --- .../core/function/editor/FunctionData.java | 2 +- .../program/model/lang/PrototypeModel.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java index a66dc66688..4054cc13af 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionData.java @@ -218,7 +218,7 @@ class FunctionData extends FunctionDataView { } VariableStorage[] paramStorage = - effectiveCallingConvention.getStorageLocations(getProgram(), dataTypes, true); + effectiveCallingConvention.getStorageLocations(getProgram(), dataTypes, true, hasVarArgs); returnInfo.setStorage(paramStorage[0]); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java index fef08a80ca..2793543343 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java @@ -398,6 +398,30 @@ public class PrototypeModel { */ public VariableStorage[] getStorageLocations(Program program, DataType[] dataTypes, boolean addAutoParams) { + return getStorageLocations(program, dataTypes, addAutoParams, false); + } + + /** + * Calculate input and output storage locations given a function prototype, + * with optional variable-argument support. + *

+ * This overload additionally sets {@link PrototypePieces#firstVarArgSlot} when + * {@code isVarArgs} is true, enabling {@code VarargsFilter}-based calling-convention + * rules (e.g. {@code } in a .cspec) to be applied correctly. + * + * @param program is the Program + * @param dataTypes return/parameter datatypes (first element is always the return datatype, + * i.e., minimum array length is 1) + * @param addAutoParams true if auto-parameter storage locations can be generated + * @param isVarArgs true if the function takes variable arguments; when true, all + * data-types supplied in {@code dataTypes} are treated as non-optional and the first + * vararg slot is set to immediately follow the last supplied parameter + * @return dynamic storage locations ordered by ordinal where first element corresponds to + * return storage. The returned array may also include additional auto-parameter storage + * locations. + */ + public VariableStorage[] getStorageLocations(Program program, DataType[] dataTypes, + boolean addAutoParams, boolean isVarArgs) { DataType injectedThis = null; if (addAutoParams && hasThis) { @@ -406,6 +430,10 @@ public class PrototypeModel { injectedThis = new PointerDataType(program.getDataTypeManager()); } PrototypePieces proto = new PrototypePieces(this, dataTypes, injectedThis); + if (isVarArgs) { + // All supplied parameters are non-optional; varargs begin immediately after them. + proto.firstVarArgSlot = proto.intypes.size(); + } ArrayList res = new ArrayList<>(); assignParameterStorage(proto, program.getDataTypeManager(), res, addAutoParams);