ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
Subject: virtual bug
From: Michael Sporn <sporn@mathematik.hu-berlin.de>
Date: Wed, 17 Feb 1999 21:56:37 +0100 (MET)
Type: Patch
State: Done: applied.
See also: b-981201, b-981208-4, b-990217-0, b-990217-1.

Hallo Lars, ich hoffe du hast den 40-minuetigen Weg gut ueberstanden...

Also zur Erlaeuterung:

Der erste Bug is der in b-981201 beschriebene. Es liegt an dem expliziten
call in die virtuelle basisklasse. In dem Beispiel tritt das Problem
in der Funktion bar() auf: ruft sie explizit d::foo() auf, setzt der inter-
preter current_variables falsch. Das liegt daran, dass normalerweise d's
variablen direkt vor denen von c liegen, aber da die inheritance virtual
ist, der variablenblock von d an den anfang der variablen von a geschoben wird.
Das dumme is, dass man bei kompilation von c nicht wissen kann, an welchem
ort die variablen von d letzten endes stehen werden, so dass man den
index in der inherit-liste von a (zur Laufzeit) jedesmal neu bestimmen muss.
Genau das ist nicht gemacht worden.
Wenn also ein expliziter call in eine virtuelle Basisklasse gemacht wird,
durchsucht der interpreter jetzt jedesmal die inherit liste des objekts in
dem das programm grade laeuft. Die Art und Weise, wie er das tut, is die
trivialste; wenn es sehr grosse inheritbaeume mit vielen virtual klassen
sind, is es vermutlich nich sehr effektiv. Aber ich denke, normalerweise
is es ausreichend.

Der zweite is in b-981208-4 beschrieben. Der effekt entsteht dadurch, dass
virtual geerbte klassen in die inheritliste uebernommen werden auch wenn sie
nicht direkt geerbt werden. Das wird gemacht, um die offsets fuer die
virtuellen variablen bei funktionsaufrufen in diese klassen extra abzulegen.
Wird ein :: bearbeitet, ignoriert der compiler aber, dass es keine direkt
geerbten klassen sind. Im Beispiel ist die inherit liste von c 'ab' und nich
'b', so dass :: zuerst in a nach foo sucht und auch findet.
Ich hab nun in prolang.y einen weiteren mem_block dazu genommen, um jedesmal
wenn eine klasse in die inherit liste uebernommen wird, ein flag zu setzen, ob
das ein richtiges inherit is oder eins wegen virtual.  Das flag wird dann in
:: abgetestet.

Eine Sache war mich nicht 100% klar, und zwar in dem "*":: fall (in
insert_inherited()). Da steht weiter unter ein continue, das ich recht
unlogisch fand, selbst bei dem alten verhalten. Lies dir bitte den kommentar
durch und schau, ob ich recht hab oder nicht.

Eine Sache, die man vielleicht ins Auge fassen kann ist, die inherit
liste ein wenig sauberer zu machen (vielleicht alle extra virtual zuerst
und die dann auch nicht mehr als einmal). Man koennte den lookup zur
Laufzeit optimieren und f_inherit_list() verbessern (die gibt naemlich
auch die extra inherits aus).

Mein Gott, ich haette nich gedacht, dass ich so viel schreiben wuerde.
Ich hoffe, der text hat mehr zur klaerung als zur verwirrung beigetragen.;)

Das diff bezieht sich auch schon auf dev-37.

Ciao, Michael

--
Michael Sporn <sporn@mathematik.hu-berlin.de>


diff -rc ldmud-dev-37/interpret.c ldmud-dev/interpret.c
*** ldmud-dev-37/interpret.c	Wed Feb 17 01:46:17 1999
--- ldmud-dev/interpret.c	Wed Feb 17 20:28:30 1999
***************
*** 4056,4061 ****
--- 4056,4105 ----
          /* Save all important global stack machine registers */
          push_control_stack(sp, pc+1, fp);

+         /* if we do an explicit call into a virtually inherited base class we
+          * have to look up the position of the virtual variables anew, this
+          * cannot be done at compile time because it depends on the _object_
+          * (i.e. the runtime environment) in which current_prog is running
+          */
+         if (current_prog != current_object->prog &&
+                 inheritp->prog->num_variables &&
+                 (current_prog->variable_names
+                  [inheritp->variable_index_offset +
+                  inheritp->prog->num_variables-1].flags & TYPE_MOD_VIRTUAL) &&
+                 !(inheritp->prog->variable_names
+                     [inheritp->prog->num_variables-1].flags & TYPE_MOD_VIRTUAL))
+         {
+             /* now lookup the inheritp of the virtually inherited program
+                in the inherit list of the topmost program */
+             int i = current_object->prog->num_inherited;
+             struct inherit *inh = current_object->prog->inherit;
+             while (i) {
+                 if (inh->prog == inheritp->prog &&
+                         current_object->prog->variable_names[
+                         inh->variable_index_offset +
+                         inh->prog->num_variables-1].flags&TYPE_MOD_VIRTUAL)
+                     break;
+                 inh++;
+                 i--;
+             }
+             if (i) { /* found, so adjust the inheritp and the offsets
+                         to start with */
+                 inheritp = inh;
+                 current_variables = current_object->variables;
+                 function_index_offset = 0;
+             } else { /* this shouldn't happen ! */
+ #ifdef DEBUG
+                 fprintf(stderr,
+                         "Adjusting variable offsets because of virtual "
+                         "inheritance for call from %s into %s (topmost "
+                         "program %s) FAILED, please check the inherit "
+                         "tree and report it.\n",
+                         current_prog->name, inheritp->prog->name,
+                         current_object->prog->name);
+ #endif
+             }
+         }
+
          /* This assigment must be done after push_control_stack() */
          current_prog = inheritp->prog;
          /*
diff -rc ldmud-dev-37/prolang.y ldmud-dev/prolang.y
*** ldmud-dev-37/prolang.y	Mon Feb 15 02:12:14 1999
--- ldmud-dev/prolang.y	Wed Feb 17 20:30:23 1999
***************
*** 58,64 ****
  %endif /* INITIALIZATION_BY___INIT */
  #define A_STRING_NEXT               11
  #define A_INCLUDE_NAMES        12
! #define NUMAREAS               13

  #define CURRENT_PROGRAM_SIZE (mem_block[A_PROGRAM].current_size)

--- 58,66 ----
  %endif /* INITIALIZATION_BY___INIT */
  #define A_STRING_NEXT               11
  #define A_INCLUDE_NAMES        12
! #define A_INHERIT_FLAG         13  /* is 1 if the corresponding inherit
!                                       is additional due to virtual */
! #define NUMAREAS               14

  #define CURRENT_PROGRAM_SIZE (mem_block[A_PROGRAM].current_size)

***************
*** 1488,1493 ****
--- 1490,1496 ----
                        (char *)&inherit,
                        sizeof inherit
                      );
+                     byte_to_mem_block(A_INHERIT_FLAG, 0);
                      num_virtual_variables =
                        mem_block[A_VIRTUAL_VAR].current_size /
                          sizeof (struct variable);
***************
*** 5932,5937 ****
--- 5935,5941 ----
  {
      struct inherit *ip;
      int num_inherits, super_length;
+     int ix;

      while(*super_name == '/')
          super_name++;
***************
*** 5940,5951 ****
          sizeof (struct inherit);
      real_name = findstring(real_name);
      ip = (struct inherit *)mem_block[A_INHERITS].block;
!     for (; num_inherits > 0; ip++, num_inherits--) {
          short i;
          uint32 flags;
          char *__PREPARE_INSERT__p = __prepare_insert__p;
          short __ADD_SHORT__s[2];

          if (*super_name) {
              /* ip->prog->name includes .c */
              int l = strlen(ip->prog->name + 2);
--- 5944,5960 ----
          sizeof (struct inherit);
      real_name = findstring(real_name);
      ip = (struct inherit *)mem_block[A_INHERITS].block;
!     ix = 0;
!     for (; num_inherits > 0; ix++, ip++, num_inherits--) {
          short i;
          uint32 flags;
          char *__PREPARE_INSERT__p = __prepare_insert__p;
          short __ADD_SHORT__s[2];

+         if (mem_block[A_INHERIT_FLAG].block[ix] != 0) /* this is an
+                                                          additional inherit */
+             continue;
+
          if (*super_name) {
              /* ip->prog->name includes .c */
              int l = strlen(ip->prog->name + 2);
***************
*** 6006,6022 ****
      if (strpbrk(super_name, "*?") && !num_arg) {
          int calls = 0;
          short i = -1;
          *super_p = 0;
          num_inherits = mem_block[A_INHERITS].current_size /
              sizeof (struct inherit);
          ip = (struct inherit *)mem_block[A_INHERITS].block;
!         for (; num_inherits > 0; ip++, num_inherits--) {
              uint32 flags;
              PREPARE_S_INSERT(6)

              /* ip->prog->name includes .c */
              int l = strlen(ip->prog->name + 2);

              if ( !match_string(super_name, ip->prog->name, l) )
                  continue;
              if ( (i = find_function(real_name, ip->prog)) < 0)
--- 6015,6036 ----
      if (strpbrk(super_name, "*?") && !num_arg) {
          int calls = 0;
          short i = -1;
+         int ix;
          *super_p = 0;
          num_inherits = mem_block[A_INHERITS].current_size /
              sizeof (struct inherit);
          ip = (struct inherit *)mem_block[A_INHERITS].block;
!         ix = 0;
!         for (; num_inherits > 0; ip++, ix++, num_inherits--) {
              uint32 flags;
              PREPARE_S_INSERT(6)

              /* ip->prog->name includes .c */
              int l = strlen(ip->prog->name + 2);

+             if (mem_block[A_INHERIT_FLAG].block[ix] != 0) /*additional
+                                                             inherit */
+                 continue;
              if ( !match_string(super_name, ip->prog->name, l) )
                  continue;
              if ( (i = find_function(real_name, ip->prog)) < 0)
***************
*** 6036,6044 ****
--- 6050,6080 ----
                    !(prog2->variable_names[numvar2-1].flags & TYPE_MOD_VIRTUAL) )
                  {
                      /* Inherited from a virtually inherited program */
+ #if 0
                      /* The call for the virtually program itself should
                       * be sufficent. */
+             /* wieso???? ich hab wirklich keine ahnung wozu das gut sein soll
+              *
+              * wenn man verhindern will, dass mehrfach virtuell inheritete
+              * funktionen mehrfach aufgerufen werden, sollte man
+              * das selbst in lpc machen (is ja auch in c++ so)
+              *
+              * ausserdem: wenn ein programm mehrmals virtuell
+              * inherited wird, gibt es hier 2 alternativen: entweder man
+              * macht meinen neuen obigen test, was zur folge hat, dass
+              * die funktion in der klasse ueberhaupt nicht aufgerufen wird,
+              * oder man macht ihn nicht und ruft somit die funktion in
+              * allen zusaetzlichen inherits auf (also potentiell
+              * mehrfach) UND hat den bug a la ::f(), d.h. eigentlich
+              * ueberladene funktionen werden auch aufgerufen
+              *
+              * wenn ich mich jedoch irren sollte, nimm es wieder rein
+              */
                      continue;
+ #else
+                     do --ip; while (ip->prog != prog2);
+                     i -= ip2->function_index_offset;
+ #endif
                  }
              }
              add_f_byte(F_CALL_EXPLICIT_INHERITED);
***************
*** 6644,6649 ****
--- 6680,6686 ----
                     sizeof(struct inherit) - 1;
                  inherit.function_index_offset += fun_index_offset;
                  add_to_mem_block(A_INHERITS, (char *)&inherit, sizeof inherit);
+                 byte_to_mem_block(A_INHERIT_FLAG, 1);
                  /* If a function is directly inherited from a program that
                   * introduces a virtual variable, the code therein is not
                   * aware of virtual inheritance. For this reason, there are