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

RTTI hook type erasure is considered undefined behavior by clang #1424

Open
alaviss opened this issue Aug 19, 2024 · 3 comments
Open

RTTI hook type erasure is considered undefined behavior by clang #1424

alaviss opened this issue Aug 19, 2024 · 3 comments
Labels
bug Something isn't working compiler/backend Related to backend system of the compiler

Comments

@alaviss
Copy link
Contributor

alaviss commented Aug 19, 2024

Example

type
  X = object of RootObj

proc `=destroy`(x: var X) =
  discard

proc main() =
  var x: ref RootObj = (ref X)()

main()

Actual Output

Note that a recent clang version (>= 17) is required.

$ nim r --cc:clang --passC:-fsanitize=function --passL:-fsanitize=function test.nim

cache/nimskull/test_d/stdlib_system.nim.c:2046:3: runtime error: call to function eqdestroy___test_2 through pointer to incorrect function type 'void (*)(void *)'

Possible Solution

Generate generic thunks for hooks called via RTTI. For example

void eqdestroy_thunk___test_2(void* ptr) {
  eqdestroy___test_2((X*) ptr);
}

Alternatively type erase eqdestroy/eqtrace parameters, but that spells trouble if anyone uses =destroy/=trace as function pointers.

References

Many other projects are also dealing with the fallout:

Apparently this new UB warning has to do with CFI (Control Flow Integrity) protections.

@alaviss alaviss added bug Something isn't working compiler/backend Related to backend system of the compiler labels Aug 19, 2024
@zerbina
Copy link
Collaborator

zerbina commented Aug 19, 2024

Hm, that's annoying, but it does make sense, given that the current implementation violates the C standard.

Once the new RTTI handling is in place, this should be relatively easy to fix in an okay fashion; the creation logic for RTTI objects would simply request thunk procedures as needed.

Alternatively type erase eqdestroy/eqtrace parameters, but that spells trouble if anyone uses =destroy/=trace as function pointers.

In general, I think manually calling hook procedures (or taking their address) should be disallowed. Doing so is error prone, and it also - like you said - prevents the compiler from doing some internal adjustments to them.

@alaviss
Copy link
Contributor Author

alaviss commented Aug 21, 2024

In general, I think manually calling hook procedures (or taking their address) should be disallowed. Doing so is error prone, and it also - like you said - prevents the compiler from doing some internal adjustments to them.

I don't think that will float really well, unless we rethink how hooks are defined.

Hooks are currently just procs shaped in a certain way, so I'd prefer that they continue to have the same capabilities as one.

@zerbina
Copy link
Collaborator

zerbina commented Aug 21, 2024

Hooks are currently just procs shaped in a certain way, so I'd prefer that they continue to have the same capabilities as one.

There are already restrictions placed on hook procedures (e.g., cannot rebind, must be in same module as type, must not raise), so I disagree that they're just procedures shaped in a certain way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compiler/backend Related to backend system of the compiler
Projects
None yet
Development

No branches or pull requests

2 participants