Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix memory mismanagement bug with EventAttachInfo #268

Merged
merged 4 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ If you make changes to the [package TypeScript files](./package/src/), be sure t

### Prepare and submit a PR
1. Once changes are ready, run `yarn change` at the root of the repository to create a patch (it will ask for a description of the change). The version scheme we use is [SemVer](https://semver.org/)
2. Update the package version by running `yarn bump`
3. Open a pull request and address review feedback.
4. After the PR is merged, manually trigger a publish from GitHub to publish to npm.

## Technical details
You can find more details to setting up in the [Technical Guide](TechnicalGuide.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fix EventAttachInfo struct so it holds onto a ref-counted instance of XamlMetadata, as well as removes dangerous pass-by-reference instances when dealing with async code.",
"packageName": "react-native-xaml",
"email": "[email protected]",
"dependentChangeType": "patch"
}
36 changes: 18 additions & 18 deletions package/Codegen/TypeEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,28 +59,28 @@ public virtual string TransformText()
"\r\n__declspec(noinline) T DoTheTypeChecking(const winrt::Windows::Foundation::IIn" +
"spectable& ii, bool isWrapped) {\r\n auto o = isWrapped ? Unwrap<T>(ii) : ii.try_" +
"as<T>();\r\n return o;\r\n}\r\n\r\ntemplate<typename T>\r\n__declspec(noinline) void Disp" +
"atchTheEvent(const EventAttachInfo& eai, const winrt::Windows::Foundation::IInsp" +
"ectable& sender, const T& args) {\r\n auto senderAsFE = sender.try_as<FrameworkEl" +
"ement>();\r\n auto wEN = winrt::to_hstring(eai.jsEventName);\r\n if (eai.xamlMetad" +
"ata.m_receiveEvent.has_value()) {\r\n const auto tag = XamlMetadata::TagFromEle" +
"atchTheEvent(const EventAttachInfo eai, const winrt::Windows::Foundation::IInspe" +
"ctable& sender, const T& args) {\r\n auto senderAsFE = sender.try_as<FrameworkEle" +
"ment>();\r\n auto wEN = winrt::to_hstring(eai.jsEventName);\r\n if (eai.xamlMetada" +
"ta->m_receiveEvent.has_value()) {\r\n const auto tag = XamlMetadata::TagFromEle" +
"ment(eai.obj.as<xaml::DependencyObject>());\r\n ExecuteJsi(eai.context, [metada" +
"ta = eai.xamlMetadata.shared_from_this(), tag, senderAsFE, args, eventName = eai" +
".jsEventName](facebook::jsi::Runtime& rt) {\r\n auto objSender = std::make_sh" +
"ared<XamlObject>(senderAsFE, metadata);\r\n auto objArgs = std::make_shared<X" +
"amlObject>(args, metadata);\r\n auto obj = std::make_shared<facebook::jsi::Ob" +
"ject>(rt);\r\n obj->setProperty(rt, \"sender\", rt.global().createFromHostObjec" +
"t(rt, objSender));\r\n obj->setProperty(rt, \"args\", rt.global().createFromHos" +
"tObject(rt, objArgs));\r\n\r\n metadata->JsiDispatchEvent(rt, tag, std::string(" +
"eventName), obj);\r\n });\r\n }\r\n else {\r\n XamlUIService::FromContext(eai." +
"context).DispatchEvent(eai.obj.try_as<xaml::FrameworkElement>(), wEN.c_str(),\r\n " +
" [senderAsFE, args](const winrt::Microsoft::ReactNative::IJSValueWriter& evt" +
"DataWriter) {\r\n SerializeEventArgs(evtDataWriter, senderAsFE, args);\r\n " +
" });\r\n }\r\n};\r\n\r\n/*static*/ const EventInfo EventInfo::xamlEventMap[] = {\r\n");
"ta = eai.xamlMetadata, tag, senderAsFE, args, eventName = eai.jsEventName](faceb" +
"ook::jsi::Runtime& rt) {\r\n auto objSender = std::make_shared<XamlObject>(se" +
"nderAsFE, metadata);\r\n auto objArgs = std::make_shared<XamlObject>(args, me" +
"tadata);\r\n auto obj = std::make_shared<facebook::jsi::Object>(rt);\r\n o" +
"bj->setProperty(rt, \"sender\", rt.global().createFromHostObject(rt, objSender));\r" +
"\n obj->setProperty(rt, \"args\", rt.global().createFromHostObject(rt, objArgs" +
"));\r\n\r\n metadata->JsiDispatchEvent(rt, tag, std::string(eventName), obj);\r\n" +
" });\r\n }\r\n else {\r\n XamlUIService::FromContext(eai.context).DispatchEv" +
"ent(eai.obj.try_as<xaml::FrameworkElement>(), wEN.c_str(),\r\n [senderAsFE, a" +
"rgs](const winrt::Microsoft::ReactNative::IJSValueWriter& evtDataWriter) {\r\n " +
" SerializeEventArgs(evtDataWriter, senderAsFE, args);\r\n });\r\n }\r\n};\r\n\r\n" +
"/*static*/ const EventInfo EventInfo::xamlEventMap[] = {\r\n");
foreach (var evt in Events) {
this.Write(" {\"");
this.Write(this.ToStringHelper.ToStringWithCulture(evt.GetName()));
this.Write("\", [](const EventAttachInfo& eai, bool isWrapped, winrt::event_token token) noexc" +
"ept {\r\n if (const auto& c = DoTheTypeChecking<");
this.Write("\", [](const EventAttachInfo eai, bool isWrapped, winrt::event_token token) noexce" +
"pt {\r\n if (const auto& c = DoTheTypeChecking<");
this.Write(this.ToStringHelper.ToStringWithCulture(Util.GetCppWinRTType(evt.DeclaringType)));
this.Write(">(eai.obj, isWrapped)) {\r\n if (!token) {\r\n return c.");
this.Write(this.ToStringHelper.ToStringWithCulture(evt.GetName()));
Expand Down
8 changes: 4 additions & 4 deletions package/Codegen/TypeEvents.tt
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ __declspec(noinline) T DoTheTypeChecking(const winrt::Windows::Foundation::IInsp
}

template<typename T>
__declspec(noinline) void DispatchTheEvent(const EventAttachInfo& eai, const winrt::Windows::Foundation::IInspectable& sender, const T& args) {
__declspec(noinline) void DispatchTheEvent(const EventAttachInfo eai, const winrt::Windows::Foundation::IInspectable& sender, const T& args) {
auto senderAsFE = sender.try_as<FrameworkElement>();
auto wEN = winrt::to_hstring(eai.jsEventName);
if (eai.xamlMetadata.m_receiveEvent.has_value()) {
if (eai.xamlMetadata->m_receiveEvent.has_value()) {
const auto tag = XamlMetadata::TagFromElement(eai.obj.as<xaml::DependencyObject>());
ExecuteJsi(eai.context, [metadata = eai.xamlMetadata.shared_from_this(), tag, senderAsFE, args, eventName = eai.jsEventName](facebook::jsi::Runtime& rt) {
ExecuteJsi(eai.context, [metadata = eai.xamlMetadata, tag, senderAsFE, args, eventName = eai.jsEventName](facebook::jsi::Runtime& rt) {
auto objSender = std::make_shared<XamlObject>(senderAsFE, metadata);
auto objArgs = std::make_shared<XamlObject>(args, metadata);
auto obj = std::make_shared<facebook::jsi::Object>(rt);
Expand All @@ -64,7 +64,7 @@ __declspec(noinline) void DispatchTheEvent(const EventAttachInfo& eai, const win

/*static*/ const EventInfo EventInfo::xamlEventMap[] = {
<# foreach (var evt in Events) { #>
{"<#= evt.GetName() #>", [](const EventAttachInfo& eai, bool isWrapped, winrt::event_token token) noexcept {
{"<#= evt.GetName() #>", [](const EventAttachInfo eai, bool isWrapped, winrt::event_token token) noexcept {
if (const auto& c = DoTheTypeChecking<<#= Util.GetCppWinRTType(evt.DeclaringType) #>>(eai.obj, isWrapped)) {
if (!token) {
return c.<#= evt.GetName() #>([eai] (<#= Util.GetCppWinRTEventSignature(evt) #>) noexcept {
Expand Down
Loading
Loading