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

[MSVC][x86] Failed to build with error C2488: 'naked' can only be applied to non-member function definitions #104460

Open
NEIL-smtg opened this issue Jul 5, 2024 · 5 comments
Labels
area-Infrastructure-coreclr help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@NEIL-smtg
Copy link

NEIL-smtg commented Jul 5, 2024

Description

Note:
To reproduce this, you'll need wait for VS 2022 17.12 Preview or later version to ship which will contain this change.

Recently, we have been building this project using the latest build of MSVC, and we have encountered the following error:

runtime\src\coreclr\debug\ee\debugger.cpp(13904) :
error C2488: 'Debugger::GenericHijackFunc': 'naked' can only be applied to non-member function definitions

Complete build log: Build.log

Reproduction Steps

  1. Open X86 Native Tools Command Prompt for VS 2022
  2. git clone https://github.com/dotnet/runtime.git
  3. cd runtime
  4. set CL=/wd5281
  5. .\build.cmd -subset clr+libs -c release -arch x86 2>&1

Expected behavior

It compiles.

Actual behavior

runtime\src\coreclr\debug\ee\debugger.cpp(13904) :
error C2488: 'Debugger::GenericHijackFunc': 'naked' can only be applied to non-member function definitions

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

This is the narrowed down repro, test.cpp:

struct Foo {
    __declspec(naked) void func1() {} // gets C2488
    void func2();
    __declspec(naked) static void func3() {} // gets C2488
};

#if defined(TARGET_X86)
__declspec(naked)
#endif
void Foo::func2() {} // should also get C2488

repro command:

cl /c test.cpp /DTARGET_X86

For current version, you will only ger error C2488 on line 2 and 4. For the upcoming version of VS, the last line will be also getting the error C2488.

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 5, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jul 5, 2024
@NEIL-smtg NEIL-smtg changed the title [MSVC][x86] Failed to build with error C2488: 'Debugger::GenericHijackFunc': 'naked' can only be applied to non-member function definitions [MSVC][x86] Failed to build with error C2488: 'naked' can only be applied to non-member function definitions Jul 5, 2024
Copy link
Contributor

Tagging subscribers to this area: @hoyosjs
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan huoyaoyuan removed the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 5, 2024
@huoyaoyuan
Copy link
Member

This was touched in #102834, but it was already naked then.

Does it make sense to port the naked function to asm now?

@jkotas
Copy link
Member

jkotas commented Jul 5, 2024

Does it make sense to port the naked function to asm now?

Yes. Inline assembler has always been a factory for problems. We try to avoid inline asm for any new code.

@jkotas jkotas added the help wanted [up-for-grabs] Good issue for external contributors label Jul 5, 2024
@huoyaoyuan
Copy link
Member

Well I want to understand more about this specific function:

//
// This is the function that a thread is hijacked to by the Right Side during a variety of debug events. This function
// must be naked.
//
#if defined(TARGET_X86)
#ifdef TARGET_WINDOWS
__declspec(naked)
#else
__attribute__((naked))
#endif
#endif // defined (_x86_)
void Debugger::GenericHijackFunc(void)
{
#if defined(TARGET_X86) || defined(TARGET_AMD64)
#if defined(TARGET_X86)
_asm
{
push ebp
mov ebp,esp
sub esp,__LOCAL_SIZE
}
#endif
// We can't have C++ classes w/ dtors in a declspec naked, so just have call into a helper.
GenericHijackFuncHelper();
#if defined(TARGET_X86)
_asm
{
mov esp,ebp
pop ebp
}
#endif
// This signals the Right Side that this thread is ready to have its context restored.
ExceptionNotForRuntime();
#else
_ASSERTE(!"@todo - port GenericHijackFunc");
#endif // defined (_x86_)
_ASSERTE(!"Should never get here (Debugger::GenericHijackFunc)");
}

It just pushes and pops ebp frame around the call to GenericHijackFuncHelper. What's the requirement around this?

When written as ordinal function, it compiles to the same code of win-x64:

call GenericHijackFuncHelper
jmp ExceptionNotForRuntime

On win-arm64, the return-address saving is around the two function calls:

str lr,[sp,#-0x10]!
bl GenericHijackFuncHelper
bl ExceptionNotForRuntime
ldr lr,[sp],#0x10
ret

@jkotas
Copy link
Member

jkotas commented Jul 6, 2024

// On X86 Debugger::GenericHijackFunc() ensures the stack is walkable
// by simply using the EBP chain, therefore we can execute the hijack
// by setting the thread's context EIP to point to this function.
comment talks about this

@agocke agocke added this to the 9.0.0 milestone Jul 8, 2024
@agocke agocke removed the untriaged New issue has not been triaged by the area owner label Jul 8, 2024
@agocke agocke modified the milestones: 9.0.0, 10.0.0 Aug 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Infrastructure-coreclr help wanted [up-for-grabs] Good issue for external contributors
Projects
Status: No status
Development

No branches or pull requests

5 participants