Skip to content

Zero-initialize generated array-enum mask wrappers in codegen - #59703

Open
hsusul wants to merge 2 commits into
react:mainfrom
hsusul:fix/codegen-array-enum-mask-init
Open

hsusul wants to merge 2 commits into
react:mainfrom
hsusul:fix/codegen-array-enum-mask-init

Conversation

@hsusul

@hsusul hsusul commented Oct 30, 2026

Copy link
Copy Markdown

Summary:

Fixes #59561. The root cause and fix follow the diagnosis in that issue.

Array-of-enum (mask) props such as Modal's supportedOrientations can end up with bits the JS value never listed. On iOS that lets a landscape-only modal rotate to portrait.

The generated <Name>MaskWrapped struct (from GeneratePropsH.js) declares its only member without an initializer. convertRawProp in propsConversions.h default-constructs the prop type (T result;), so result.value starts indeterminate. The generated fromRawValue then ORs each listed value into it (wrapped.value |= ...), which keeps whatever bits were already in that memory. The std::optional<T> and std::vector<T> overloads of fromRawValue default-construct T the same way.

This change gives the generated member a value initializer (value{}), so every default-constructed wrapper starts at an empty mask. The existing designated ({ .value = ... }) and braced ({static_cast<...>(...)}) initializers in the generated Props.cpp are unaffected. Fixing it in the generated type covers every site that default-constructs it, without changing convertRawProp for all other prop types.

Changelog:

[GENERAL] [FIXED] - Codegen array-of-enum props (e.g. Modal supportedOrientations) no longer start parsing from an uninitialized mask

Test Plan:

Updated the GeneratePropsH snapshots (unit and both e2e suites) to expect value{};. They fail before the generator change and pass after it:

$ yarn jest packages/react-native-codegen/src/generators/components/__tests__/GeneratePropsH-test.js packages/react-native-codegen/e2e/deep_imports/__tests__/components/GeneratePropsH-test.js packages/react-native-codegen/e2e/namespaced/__tests__/components/GeneratePropsH-test.js
# before
-   ArrayPropsNativeComponentSizesMask value{};
+   ArrayPropsNativeComponentSizesMask value;
Tests:       5 failed, 69 passed, 74 total
# after
Tests:       74 passed, 74 total

Runtime check of the generated code. I compiled the mask block that GeneratePropsH emits for the ARRAY_PROPS fixture (sizes: ['small', 'large']), with stub RawValue and PropsParserContext types and a copy of convertRawProp's T result; fromRawValue(...) pattern. I used clang++ -std=c++20 -O0 -ftrivial-auto-var-init=pattern so the indeterminate start value shows up the same way on every run:

# before
sizes=['small'] -> mask=0xaaaaaaab (expected 0x00000001), toString="small, large"
# after
sizes=['small'] -> mask=0x00000001 (expected 0x00000001), toString="small"

Also ran:

  • yarn jest packages/react-native-codegen: 64 suites, 3130 tests, 1279 snapshots passed
  • yarn flow-check: 0 errors
  • yarn eslint --max-warnings 0 and prettier --check on GeneratePropsH.js: clean

Not run: an iOS or Android app build. I did not reproduce the Modal orientation behavior on a device or simulator. I did not regenerate the scripts/cxx-api snapshots. Those snapshots drop member initializers (for example bool visible{false} is recorded as bool visible), so I don't expect them to change.

Snapshot change only; fails until GeneratePropsH emits the initializer.
convertRawProp default-constructs the prop type (T result;) and the
generated fromRawValue ORs each listed value into wrapped.value, so the
mask started from an indeterminate value and could keep stray bits, e.g.
Modal supportedOrientations allowing orientations it does not list.
@meta-cla

meta-cla Bot commented Oct 30, 2026

Copy link
Copy Markdown

Hi @hsusul!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@meta-cla

meta-cla Bot commented Oct 31, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 31, 2026
@meta-cla

meta-cla Bot commented Oct 31, 2026

Copy link
Copy Markdown

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 31, 2026

This branch has not been deployed

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS] Modal supportedOrientations can allow orientations it doesn't list (codegen mask props are parsed into an uninitialized value)

1 participant