Search Issue Tracker

Won't Fix

Votes

1

Found in [Package]

1.8.19

Issue ID

BUR-2822

Regression

No

Burst Redundant Zero-Initialization On Out Parameters

Package: Burst

-

Reproduction steps:
1. Open the attached “IN-91593_SkipLocalsInitTest.zip“ project
2. Open Burst Inspector (Jobs > Burst > Open Inspector…)
3. Select the “BurstTestLargeStructV1“ under the “SkipLocalsInitTest” category
4. Observe
5. Select the “BurstTestLargeStructV2“ under the “SkipLocalsInitTest” category
6. Observe

Expected result: Burst initializes out parameters the same way as return values, stack memory is not cleared
Actual result: Burst is zero-initializing stack memory initialized by the out parameter (BurstTestLargeStructV2)

Reproducible with: 1.8.19 (2022.3.58f1, 6000.0.39f1, 6000.1.0b7, 6000.2.0a4)

Reproducible on: Windows 10 (User’s platform), M1 Max MacOS 15.1.1 (Tested by CQA)
Not reproducible on: No other environment tested

Note:
- This can be worked-around by using the [Unity.Burst.CompilerServices.SkipLocalsInit] attribute, but it shouldn't be necessary here.
- The user thinks that “Unity.Collections.LowLevel.Unsafe.UnsafeUtility” method should be added with the functional equivalence of “System.Runtime.CompilerServices.Unsafe.SkipInit<T>(out T value)”

  1. Resolution Note:

    Hello,
    So turns out this is actually not a Burst bug.
    This is because of three main factors:
    1. We have to zero-initialize variables to comply with the C#/CLI spec
    2. `out` arguments as a concept does not exist once your C# code has been compiled down to a dll/IL (which is the input Burst gets), instead it's just represented as a `ref` argument
    3. We are normally able to optimize our way out of these situations

    You can see how point 1 and 2 interaction, we have to generate the zero-initialization for the out-var and then when we can't do anything clever because a `ref` argument gives no guarantees about initialization. Normally inlining gets rid of these problems, but you've explicitly disabled that here.

    In the case of just returning the struct, all intermediate variables can get their zero-initialization skipped because the situation is more transparent to the optimizer.

    So yeah, I can recommend either relying on inlining and using [SkipLocalsInit] as you've noted.

Comments (1)

  1. chadfranklin47

    Feb 21, 2025 11:39

    Thank you, that makes sense.
    About my suggestion though, what is the current preferred way to zero-initialize structs? Assigning default(T) to them will zero-initialize them, even with [SkipLocalsInit]. The lack of a System.Runtime.CompilerServices.Unsafe.SkipInit<T>(out T value) method equivalent is tedious. It seems the only way to skip zero-initialization of structs is to write our own pseudo version of that method that doesn’t actually work… and then include [SkipLocalsInit] also.

Add comment

Log in to post comment

All about bugs

View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.