Skip to content

Conversation

@HryshcIlya
Copy link

Description

This PR fixes a critical bug in the Lua scripting backend that caused stack corruption when calling a UFunction with an Out parameter that was not a FStructProperty or FArrayProperty.

The Problem:

The internal function call_ufunction_from_lua correctly identifies Out parameters and expects a placeholder Lua table on the stack. However, for Out parameters that are simple object pointers (e.g., UObject*&), the logic would continue to the next parameter without popping the placeholder table from the Lua stack.

This desynchronized the stack, causing subsequent parameters to be read incorrectly and leading to a crash.

The Solution:

A single line, lua.discard_value(), has been added to the conditional block that handles these Out parameters. This ensures the placeholder table is correctly removed from the stack, restoring proper argument processing.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How has this been tested?

The fix was tested on UE4SS build zDEV-UE4SS_v3.0.1-442-gfb22cb3 against a game running on Unreal Engine 5.4.4.

The bug was reproduced by calling a static UFunction from a Blueprint Function Library with a signature containing a reference-to-pointer Out parameter, such as:
void ExampleFunction(..., UObject*& OutObjectParam, ...);

The following conceptual test confirms the fix. On an unpatched build, this call fails. With this patch, it succeeds.

Test Script:

-- Conceptual test script
local LibraryCDO = StaticFindObject("/Path/To/Some/FunctionLibrary_C.Default__FunctionLibrary_C")
local SomeContext = ... -- a valid UObject, e.g., from FindFirstOf("World")

if LibraryCDO and SomeContext then
    -- The 3rd parameter is the problematic Out-parameter
    local out_param_placeholder = {}
    
    local success, err = pcall(LibraryCDO.FunctionWithOutParam, LibraryCDO, arg1, arg2, out_param_placeholder, SomeContext)

    if success then
        print("SUCCESS: The call succeeded and the placeholder table was correctly populated.")
    else
        print("FAILURE: The call failed with a stack error.")
    end
end

Checklist

  • I have commented my code, particularly in hard-to-understand areas.
  • I have made corresponding changes to the documentation. (No documentation changes are required for this fix.)
  • I have added the necessary description of this PR to the changelog, and I have followed the same format as other entries.
  • Any dependent changes have been merged and published in downstream modules.

When a UFunction with an Out-parameter that is not a Struct or Array
is called from Lua, a placeholder table is expected on the stack.

The previous logic did not pop this placeholder table from the stack,
leading to stack desynchronization on subsequent parameter processing
and causing a crash or incorrect behavior.

This commit adds the necessary  to ensure the
stack is correctly handled, resolving the issue.
@HryshcIlya HryshcIlya force-pushed the fix/lua-out-param-stack branch from 7aae0ca to bf3d5a2 Compare July 7, 2025 08:23
@HryshcIlya HryshcIlya marked this pull request as ready for review July 7, 2025 08:23
@narknon narknon requested a review from UE4SS July 29, 2025 14:08
UE4SS
UE4SS previously approved these changes Aug 19, 2025
@UE4SS UE4SS dismissed their stale review August 19, 2025 13:53

Requires testing.
It's been a long time since I looked at this part of the code, and I no longer remember why we have the special case for structs and arrays, so I'm not sure if this is the correct fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants