Comment #0 by destructionator — 2019-12-19T19:18:35Z
Encountered this during my android/jni stuff. Easier to describe with code than with words:
----
mixin template Impl(T, string name){
alias a = __traits(getMember, T, name); // comment this and it works
static void impl() {
auto t = new T();
__traits(getMember, t, name)();
}
}
class A(CRTP) {
static foreach(memberName; __traits(derivedMembers, CRTP))
mixin Impl!(CRTP, memberName);
}
class Foo : A!Foo {
void test() {
import core.stdc.stdio;
printf("Success\n");
}
}
void main() {
Foo.impl();
}
----
Compiles successfully. Running it leads to crash.
Make `class Foo` into `final class Foo` and it works.
Put `final` on `void test` instead and it works here, but adding more members can result in the wrong method being called. Leads me to believe the virtual function slot gets confused.
Comment that `alias a = ....` line in there and it works. So the fundamental problem is related to the alias being present in the mixin template, even if never used.
So the alias of the virtual derived member appearing in the base class. However, I believe the use of the curiously-recurring template pattern is necessary to trigger the bug though since I've been unable to reproduce the crash without that.
This is the most I have been able to minimize it... the original version is:
---
mixin template Impl(T, alias a) {
static void impl() {
auto t = new T();
__traits(getMember, t, __traits(identifier, a))();
}
}
class A(CRTP) {
static foreach(memberName; __traits(derivedMembers, CRTP))
mixin Impl!(CRTP, __traits(getMember, CRTP, memberName));
}
class Foo : A!Foo {
void test() {
import core.stdc.stdio;
printf("Success\n");
}
}
void main() {
Foo.impl();
}
---
And I think it is worth noting that one too: just *passing* the alias to the mixin template also results in the same behavior. It doesn't have to explicitly mixin the alias, as long as it is present there.
reduced further
```
mixin template Impl(T){
alias a = __traits(getMember, T, "test");
//alias a = T.test; // no vtbl corruption with this alias
}
class A(T) {
mixin Impl!T;
}
class Foo : A!Foo {
void test() {}
}
void main() {
(new Foo).test();
}
```
Comment #3 by b2.temp — 2023-03-23T00:33:38Z
The same corruption without the getMember trait:
```
mixin template Impl(T){
alias a = T.test;
pragma(msg, typeof(a)); // launch dsymbolsema and corrupt vtbl
}
class A(T) {
mixin Impl!T;
}
class Foo : A!Foo {
void test() {}
}
void main() {
(new Foo).test();
}
```
Comment #4 by b2.temp — 2023-03-23T07:28:49Z
Finally the generic reproduction
```
class Base
{
alias a = Derived.test;
pragma(msg, typeof(a)); // triggers the vtbl corruption
}
class Derived : Base
{
void test(){}
}
void main()
{
(new Derived).test();
}
```
Comment #5 by robert.schadek — 2024-12-13T19:06:33Z