For React Native.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/actctx.c | 19 +++++++++++++++++++ dlls/ntdll/ntdll.spec | 2 +- include/winternl.h | 11 +++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 9828d90d11d..7fbc51f29e1 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -5435,6 +5435,25 @@ NTSTATUS WINAPI RtlActivateActivationContext( ULONG unknown, HANDLE handle, PULO return RtlActivateActivationContextEx( 0, NtCurrentTeb(), handle, cookie ); }
+/****************************************************************** + * RtlActivateActivationContextUnsafeFast (NTDLL.@) + * + * FIXME: function prototype might be wrong + */ +RTL_ACTIVATION_CONTEXT_STACK_FRAME * FASTCALL RtlActivateActivationContextUnsafeFast( RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED *frame_extended, + PVOID context ) +{ + ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer; + + TRACE( "%p %p\n", frame_extended, context ); + + frame_extended->Frame.Previous = actctx_stack->ActiveFrame; + frame_extended->Frame.ActivationContext = context; + frame_extended->Frame.Flags = 0x20; + actctx_stack->ActiveFrame = &frame_extended->Frame; + RtlAddRefActivationContext( context ); + return &frame_extended->Frame; +}
/****************************************************************** * RtlActivateActivationContextEx (NTDLL.@) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 4e36bfe2662..f79dfd50da5 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -484,7 +484,7 @@ @ stdcall RtlAcquireSRWLockShared(ptr) @ stdcall RtlActivateActivationContext(long ptr ptr) @ stdcall RtlActivateActivationContextEx(long ptr ptr ptr) -@ stub RtlActivateActivationContextUnsafeFast +@ stdcall -fastcall RtlActivateActivationContextUnsafeFast(ptr ptr) @ stdcall RtlAddAccessAllowedAce(ptr long long ptr) @ stdcall RtlAddAccessAllowedAceEx(ptr long long long ptr) @ stdcall RtlAddAccessAllowedObjectAce(ptr long long long ptr ptr ptr) diff --git a/include/winternl.h b/include/winternl.h index 86f5f4e5480..76d719ffac9 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -231,6 +231,17 @@ typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME ULONG Flags; } RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME;
+typedef struct _RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED +{ + SIZE_T Size; + ULONG Format; + RTL_ACTIVATION_CONTEXT_STACK_FRAME Frame; + PVOID Extra1; + PVOID Extra2; + PVOID Extra3; + PVOID Extra4; +} RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED, *PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED; + typedef struct _ACTIVATION_CONTEXT_STACK { RTL_ACTIVATION_CONTEXT_STACK_FRAME *ActiveFrame;
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/ntdll/actctx.c | 17 +++++++++++++++++ dlls/ntdll/ntdll.spec | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 7fbc51f29e1..03f98391538 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -5455,6 +5455,23 @@ RTL_ACTIVATION_CONTEXT_STACK_FRAME * FASTCALL RtlActivateActivationContextUnsafe return &frame_extended->Frame; }
+/****************************************************************** + * RtlDeactivateActivationContextUnsafeFast (NTDLL.@) + * + * FIXME: function prototype might be wrong + */ +VOID FASTCALL RtlDeactivateActivationContextUnsafeFast( RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED *frame_extended ) +{ + ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer; + RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; + + TRACE( "%p\n", frame_extended ); + + frame = actctx_stack->ActiveFrame; + actctx_stack->ActiveFrame = frame_extended->Frame.Previous; + RtlReleaseActivationContext( frame ); +} + /****************************************************************** * RtlActivateActivationContextEx (NTDLL.@) */ diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index f79dfd50da5..78da963b969 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -606,7 +606,7 @@ @ stub RtlCutoverTimeToSystemTime @ stdcall RtlDeNormalizeProcessParams(ptr) @ stdcall RtlDeactivateActivationContext(long long) -@ stub RtlDeactivateActivationContextUnsafeFast +@ stdcall -fastcall RtlDeactivateActivationContextUnsafeFast(ptr) @ stub RtlDebugPrintTimes @ stdcall RtlDecodePointer(ptr) @ stdcall RtlDecodeSystemPointer(ptr) RtlDecodePointer
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/kernel32/tests/actctx.c | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+)
diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index ca24ed10549..cc490f984e3 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -31,6 +31,9 @@
static BOOL (WINAPI *pQueryActCtxSettingsW)(DWORD,HANDLE,LPCWSTR,LPCWSTR,LPWSTR,SIZE_T,SIZE_T*);
+static PRTL_ACTIVATION_CONTEXT_STACK_FRAME (FASTCALL *pRtlActivateActivationContextUnsafeFast)(PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED, + PVOID); +static VOID (FASTCALL *pRtlDeactivateActivationContextUnsafeFast)(PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED); static NTSTATUS(NTAPI *pRtlFindActivationContextSectionString)(DWORD,const GUID *,ULONG,PUNICODE_STRING,PACTCTX_SECTION_KEYED_DATA); static BOOLEAN (NTAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING, PCSZ); static VOID (NTAPI *pRtlFreeUnicodeString)(PUNICODE_STRING); @@ -3096,6 +3099,8 @@ static BOOL init_funcs(void) pQueryActCtxSettingsW = (void *)GetProcAddress( hLibrary, "QueryActCtxSettingsW" );
hLibrary = GetModuleHandleA("ntdll.dll"); + X(RtlActivateActivationContextUnsafeFast); + X(RtlDeactivateActivationContextUnsafeFast); X(RtlFindActivationContextSectionString); X(RtlCreateUnicodeStringFromAsciiz); X(RtlFreeUnicodeString); @@ -4526,6 +4531,81 @@ static void test_RtlQueryInformationActiveActivationContext(void) ReleaseActCtx( context ); }
+static void test_RtlActivateActivationContextUnsafeFast(void) +{ + RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED frame_extended1 = { 0 }, frame_extended2 = { 0 }; + HANDLE context1, context2, current_context; + RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; + BOOL ret; + + ret = GetCurrentActCtx( ¤t_context ); + ok( ret, "GetCurrentActCtx failed.\n" ); + ok( !current_context, "Got unexpected handle.\n" ); + + if (!create_manifest_file( "test1.manifest", manifest1, -1, NULL, NULL )) + { + skip( "Could not create manifest file 1.\n" ); + return; + } + if (!create_manifest_file( "test2.manifest", manifest1_1, -1, NULL, NULL )) + { + skip( "Could not create manifest file 2.\n" ); + DeleteFileA( "test1.manifest" ); + return; + } + context1 = test_create( "test1.manifest" ); + ok( context1 != INVALID_HANDLE_VALUE, "Failed to create context, error %lu.\n", GetLastError() ); + DeleteFileA( "test1.manifest" ); + context2 = test_create( "test2.manifest" ); + ok( context2 != INVALID_HANDLE_VALUE, "Failed to create context, error %lu.\n", GetLastError() ); + DeleteFileA( "test2.manifest" ); + + frame_extended1.Size = sizeof(frame_extended1); + frame_extended1.Format = 0xdeadbeef; + frame = pRtlActivateActivationContextUnsafeFast( &frame_extended1, context1 ); + /* RtlActivateActivationContextUnsafeFast() on Win7 returns a NTSTATUS */ + ok( frame == &frame_extended1.Frame || broken( frame == STATUS_SUCCESS ), "Got unexpected frame.\n" ); + ok( frame_extended1.Size == sizeof(frame_extended1), "Got unexpected Size %#Ix.\n", frame_extended1.Size ); + ok( frame_extended1.Format == 0xdeadbeef, "Got unexpected Format %#lx.\n", frame_extended1.Format ); + ok( !frame_extended1.Frame.Previous, "Got unexpected Previous.\n" ); + ok( frame_extended1.Frame.ActivationContext == context1, "Got unexpected ActivationContext.\n" ); + ok( frame_extended1.Frame.Flags == 0x20, "Got unexpected Flags %#lx.\n", frame_extended1.Frame.Flags ); + + ret = GetCurrentActCtx( ¤t_context ); + ok( current_context == context1, "Got unexpected handle.\n" ); + ReleaseActCtx( current_context ); + + frame_extended2.Size = sizeof(frame_extended2); + frame_extended2.Format = 0xdeadbeef; + frame = pRtlActivateActivationContextUnsafeFast( &frame_extended2, context2 ); + /* RtlActivateActivationContextUnsafeFast() on Win7 returns a NTSTATUS */ + ok( frame == &frame_extended2.Frame || broken( frame == STATUS_SUCCESS ), "Got unexpected frame.\n" ); + ok( frame_extended2.Size == sizeof(frame_extended2), "Got unexpected Size %#Ix.\n", frame_extended2.Size ); + ok( frame_extended2.Format == 0xdeadbeef, "Got unexpected Format %#lx.\n", frame_extended2.Format ); + ok( frame_extended2.Frame.Previous == &frame_extended1.Frame, "Got unexpected Previous.\n" ); + ok( frame_extended2.Frame.ActivationContext == context2, "Got unexpected ActivationContext.\n" ); + ok( frame_extended2.Frame.Flags == 0x20, "Got unexpected Flags %#lx.\n", frame_extended2.Frame.Flags ); + + ret = GetCurrentActCtx( ¤t_context ); + ok( current_context == context2, "Got unexpected handle.\n" ); + ReleaseActCtx( current_context ); + + pRtlDeactivateActivationContextUnsafeFast( &frame_extended2 ); + + ret = GetCurrentActCtx( ¤t_context ); + ok( current_context == context1, "Got unexpected handle.\n" ); + ReleaseActCtx( current_context ); + + pRtlDeactivateActivationContextUnsafeFast( &frame_extended1 ); + + ret = GetCurrentActCtx( ¤t_context ); + ok( ret, "GetCurrentActCtx failed.\n" ); + ok( !current_context, "Got unexpected handle.\n" ); + + ReleaseActCtx( context2 ); + ReleaseActCtx( context1 ); +} + START_TEST(actctx) { int argc; @@ -4566,5 +4646,6 @@ START_TEST(actctx) test_compatibility(); test_settings(); test_RtlQueryInformationActiveActivationContext(); + test_RtlActivateActivationContextUnsafeFast(); for (int i = 1; i <= 6; i++) run_child_process_two_dll(i); }
Nikolay Sivov (@nsivov) commented about dlls/ntdll/actctx.c:
return RtlActivateActivationContextEx( 0, NtCurrentTeb(), handle, cookie );
}
+/******************************************************************
RtlActivateActivationContextUnsafeFast (NTDLL.@)
- FIXME: function prototype might be wrong
That was fine before, when Rtl* functions were only for internal use. But now this can't be too wrong.
Nikolay Sivov (@nsivov) commented about dlls/ntdll/actctx.c:
+/******************************************************************
RtlDeactivateActivationContextUnsafeFast (NTDLL.@)
- FIXME: function prototype might be wrong
- */
+VOID FASTCALL RtlDeactivateActivationContextUnsafeFast( RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED *frame_extended ) +{
- ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer;
- RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
- TRACE( "%p\n", frame_extended );
- frame = actctx_stack->ActiveFrame;
- actctx_stack->ActiveFrame = frame_extended->Frame.Previous;
- RtlReleaseActivationContext( frame );
+}
This one should release frame->ActivationContext I think.
Nikolay Sivov (@nsivov) commented about dlls/ntdll/actctx.c:
- FIXME: function prototype might be wrong
- */
+RTL_ACTIVATION_CONTEXT_STACK_FRAME * FASTCALL RtlActivateActivationContextUnsafeFast( RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED *frame_extended,
PVOID context )
+{
- ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer;
- TRACE( "%p %p\n", frame_extended, context );
- frame_extended->Frame.Previous = actctx_stack->ActiveFrame;
- frame_extended->Frame.ActivationContext = context;
- frame_extended->Frame.Flags = 0x20;
- actctx_stack->ActiveFrame = &frame_extended->Frame;
- RtlAddRefActivationContext( context );
- return &frame_extended->Frame;
+}
Flags magic looks important. We need more tests for regular "safe" API to see what flags are set to for normal frames. Depending on how "unsafe" this is, for frames placed on stack you can't do LdrShutdownThread() in a clean way currently, because it will HeapFree() it.
On Mon Jun 16 11:14:03 2025 +0000, Nikolay Sivov wrote:
That was fine before, when Rtl* functions were only for internal use. But now this can't be too wrong.
It's very close. There are some articles online showing its prototype. I added the FIXME to note that it's not 100% correct. For example, on Win7, `RtlActivateActivationContextUnsafeFast` returns an NTSTATUS. I also see some blogs showing `RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED` might not contain Extra1~4 fields.
For `RtlDeactivateActivationContextUnsafeFast`, some say it returns an `RTL_ACTIVATION_CONTEXT_STACK_FRAME`, but I didn't figure out what it really means. Some say it returns a `void`. On Win7, it returns an NTSTATUS. I chose to return void here.
On Mon Jun 16 12:10:45 2025 +0000, Nikolay Sivov wrote:
Flags magic looks important. We need more tests for regular "safe" API to see what flags are set to for normal frames. Depending on how "unsafe" this is, for frames placed on stack you can't do LdrShutdownThread() in a clean way currently, because it will HeapFree() it.
Maybe it checks the flag in LdrShutdownThread(). I will add some tests for normal frames.
On Mon Jun 16 12:10:45 2025 +0000, Nikolay Sivov wrote:
This one should release frame->ActivationContext I think.
Good catch. Thanks.
On Mon Jun 16 14:01:52 2025 +0000, Zhiyi Zhang wrote:
Maybe it checks the flag in LdrShutdownThread(). I will add some tests for normal frames.
LdrShutdownThread() was an example of where RtlFreeThreadActivationContextStack() is called. What I meant was the you can't free such "unsafe" frame in a regular way.
On Mon Jun 16 14:05:33 2025 +0000, Nikolay Sivov wrote:
LdrShutdownThread() was an example of where RtlFreeThreadActivationContextStack() is called. What I meant was the you can't free such "unsafe" frame in a regular way.
I understand. I was saying maybe RtlFreeActivationContextStack should check the flag before calling RtlFreeHeap(). The flag may be some kind of marker. I will see if it's possible to test it.