www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1978] New: Wrong vtable call

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1978

           Summary: Wrong vtable call
           Product: D
           Version: 1.028
          Platform: PC
        OS/Version: All
            Status: NEW
          Severity: critical
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: benoit tionex.de


In the following example, the program block if compiled with -g and dmd
1.026/1.028. See the comments, there are 3 possiblilities of changes, which
should not change behaviour, but does make this program work.

I tested this only on tango. Can someone confirm this bug also on phobos? and
D2?



extern(C) int printf(char*,...);

public interface View(T){
        // changing duplicate return type to View!(T) make it work
        public Dispenser!(T) duplicate ();

        public uint size ();
        public uint mutation ();
        public int opApply (int delegate (inout T value) dg);
}

public interface Dispenser(T) : View!(T){
        public void removeAll (Iterator!(T) e);
        public void remove (Iterator!(T) e);
        public void removeAll (T element);
        public void remove (T element);
}

public interface Seq(T) :
    View!(T), // removing View!(T) interface make it work.
    Dispenser!(T)
{
        public T get(int index);
        public alias get opIndex;
}

public interface Iterator(V) {
        public bool more();
        public V get();
        int opApply (int delegate (inout V value) dg);
}

public interface GuardIterator(V) : Iterator!(V){
        public uint remaining();
}

public abstract class AbstractIterator(T) : GuardIterator!(T) {
        private View!(T) view;
        private uint mutation;
        private uint togo;

        protected this (View!(T) v) {
                view = v;
                togo = v.size();
                mutation = v.mutation();
        }
        public final uint remaining() {
                return togo;
        }
        public final bool more()  {
                return togo > 0 && mutation is view.mutation;
        }
        protected final void decRemaining() {
                --togo;
        }
}

class ArrayIterator(T) : AbstractIterator!(T)
{
        private int row;
        private T[] array;

        public this (ArraySeq!(T) seq) {
                super (seq);
                array = seq.array;
        }

        public final T get()  {
                decRemaining();
                return array[row++];
        }

        int opApply (int delegate (inout T value) dg) {
                int result;

                for (auto i=remaining(); i--;)
                    {
                    auto value = get();
                    if ((result = dg(value)) != 0)
                            break;
                    }
                return result;
        }
}

public abstract class Collection(T) : Dispenser!(T)
{
        alias View!(T)  ViewT;

        protected uint count;

        public final uint size() {
                return count;
        }
        public final uint mutation()  {
                return 0;
        }
        abstract void removeAll(T element);
        abstract void remove (T element);
        abstract void removeAll (Iterator!(T) e);
        abstract void remove (Iterator!(T) e);
}

public abstract class SeqCollection(T) : Collection!(T), Seq!(T) {

        public abstract override void remove(T it);
        public abstract override void removeAll(T it);

        public void removeAll (Iterator!(T) e) {
                while (e.more)
                       removeAll (e.get);
        }
        public void remove (Iterator!(T) e) {
                while (e.more)
                       remove (e.get);
        }
}

public class ArraySeq(T) : SeqCollection!(T), Dispenser!(T) {
        public static int minCapacity = 16;
        package T array[];
        public this () {
                this ( null, 0);
        }

        package this (T[] b, int c) {
                array = b;
                count = c;
        }

        public final Dispenser!(T) duplicate() {
            return null;
        }
        int opApply (int delegate (inout T value) dg){
                auto scope iterator = new ArrayIterator!(T)(this);
                return iterator.opApply (dg);
        }
        public final T get(int index){
                return array[index];
        }

        public final override void remove(T element){}
        public final override void removeAll(T element){}
        public void remove(Iterator!(T) it){
            super.remove(it);
        }
        public void removeAll(Iterator!(T) it){
            super.removeAll(it);
        }

}

// removing this variable decl will make it work
Seq!(Object) seq;

void main(){
    auto alist = new ArraySeq!(Object);
    foreach( el; alist ){
        printf( "shall not come here.\n" );
    }
    printf( "ready\n" );
}


-- 
Apr 08 2008
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1978






I reduced it more...

Now the example prints:
remove
ready

It does not block, but remove() is called without call.

extern(C) int printf(char*,...);

public interface View(T){
        // changing duplicate return type to View!(T) make it work
        public Dispenser!(T) duplicate ();

        public uint mutation ();
}

public interface Dispenser(T) : View!(T){
        public void removeAll (Iterator!(T) e);
        public void remove (Iterator!(T) e);
        public void removeAll (T element);
        public void remove (T element);
}

public interface Seq(T) :
    View!(T), // removing View!(T) interface make it work.
    Dispenser!(T)
{
}

public interface Iterator(V) {
        int opApply (int delegate (inout V value) dg);
}

public abstract class AbstractIterator(T) : Iterator!(T) {
        protected this (View!(T) v) {
                v.mutation();
        }
}

class ArrayIterator(T) : AbstractIterator!(T) {
        public this (ArraySeq!(T) seq) {
                super (seq);
        }

        int opApply (int delegate (inout T value) dg) {
                return 0;
        }
}

public abstract class Collection(T) : Dispenser!(T)
{
        public final uint mutation()  {
                return 0;
        }
}

// removing this intermediate class makes it work
public abstract class SeqCollection(T) : Collection!(T), Seq!(T) {

}

public class ArraySeq(T) : SeqCollection!(T)
    , Dispenser!(T) // removing this makes it work, dispenser is already
derived from SeqCollection
{

        //
        public final Dispenser!(T) duplicate() {
            return null;
        }

        public final override void remove(T element){}
        public final override void removeAll(T element){}
        public void removeAll (Iterator!(T) e) {
                printf( "removeAll\n" );
        }
        public void remove (Iterator!(T) e) {
                printf( "remove\n" );
        }

}

//import tango.util.collection.model.Seq;
//import tango.util.collection.ArraySeq;

// removing this variable decl will make it work
Seq!(Object) seq;

void main(){
    auto alist = new ArraySeq!(Object);
    auto scope iterator = new ArrayIterator!(Object)(alist);
    foreach( el; iterator ){
        printf( "shall not come here.\n" );
    }
    printf( "ready\n" );
}


-- 
Apr 08 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1978






I verified the bug with dmd 1.028 and 2.012 with phobos.


-- 
Apr 08 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1978


kamm-removethis incasoftware.de changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |wrong-code





-------
Further simplification:

extern(C) int printf(char*,...);

interface InterfaceB(T) : InterfaceA {}

interface InterfaceA{
  // changing return type to InterfaceA makes it work
  InterfaceB!(Object) func ();
}

class Foo(T) : InterfaceB!(T) {
  InterfaceB!(Object) func() {
    return null;
 }
}

void main() {
  auto foo = new Foo!(Object);

  // without this call, segfault is gone
  foo.func(); 
  printf("foo.func() call passed\n");

  InterfaceA ifA = foo;
  assert(ifA !is null);
  ifA.func(); // segfault
}


-- 
Apr 08 2008
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=1978


bugzilla digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED





Fixed dmd 1.029 and 2.013


-- 
May 11 2008