View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update | 
|---|---|---|---|---|---|
| 0000483 | LDMud 3.3 | Runtime | public | 2006-08-10 05:44 | 2018-01-29 21:57 | 
| Reporter | Gnomi | Assigned To | |||
| Priority | normal | Severity | crash | Reproducibility | always | 
| Status | resolved | Resolution | fixed | ||
| Platform | i686 | OS | Debian GNU/Linux | OS Version | 3.1 | 
| Product Version | 3.3.713 | ||||
| Fixed in Version | 3.3.716 | ||||
| Summary | 0000483: replace_program confuses variable sharing | ||||
| Description | Hi, while playing around with the pragma share_variables and replace_program, I tried to provoke a crash and succeeded: 2006.08.10 00:48:10 (free_svalue) Illegal svalue 0xc01f9d4 type 285 ... apps/closure_container <lambda ?> line 0 b9cb4cf: 98 restore_arg_frame (2: 1) line 0 b9cb4d0: 24 return (1: 0) 8555716: 24 25 72 166 50 8 4 0 No program to trace. 2006.08.10 00:48:10 LDMud aborting on fatal error. #0 0x080da4b0 in fatal (fmt=0x8141348 "\002") at simulate.c:586 586 *((char*)0) = 0/a; (gdb) bt #0 0x080da4b0 in fatal (fmt=0x8141348 "\002") at simulate.c:586 0000001 0x0807f2cf in int_free_svalue (v=0xc01f9d4) at interpret.c:1097 0000002 0x080dd92e in remove_object (ob=0xbf01748) at simulate.c:2857 0000003 0x080dda77 in handle_newly_destructed_objects () at simulate.c:2947 0000004 0x08052eea in backend () at backend.c:476 0000005 0x080a7709 in main (argc=0, argv=0x0) at main.c:615 I used the following files (and initialization by __INIT): --- i/x.c: --- int dubdidu = 20; void dummy() {} --- i/y.c: --- #pragma share_variables inherit "x"; int a = 10; int b = 10; int c = 10; int d = 10; int e = 10; int f = 10; int g = 10; int h = 10; int i = 10; int j = 10; int k = 10; int l = 10; int m = 10; int n = 10; int o = 10; int p = 10; int q = 10; int r = 10; int s = 10; int t = 10; int u = 10; int v = 10; int w = 10; int x = 10; int y = 10; int z = 10; void rpy() { replace_program(); } --- obj/z.c: --- inherit "../i/y"; void rpz() { replace_program(); } --- app.c: --- void step1() { object y = load_object(__PATH__(0) "i/y"); object z = load_object(__PATH__(0) "obj/z"); y->rpy(); z->rpz(); } void step2() { destruct(clone_object(__PATH__(0) "obj/z")); } ------------- Calling app->step1() results in three objects: i/x with the program of i/x.c and one __INITialized variable. i/y with the program of i/x.c and therefore also one __INITialized variable. obj/z with the program of i/y.c, one __INITialized variable and 26 shared variables. In this constellation the blueprint (given by the efun blueprint) of obj/z is i/y, but the program of i/y is i/x.c, so the blueprints program does not correspond to the program of its clones. When cloning obj/z by app->step2(), init_object_variables looks for the blueprint and copies shared variables from the blueprint. But as the blueprint (i/y with the program i/x.c) does only have one variable, the needed 26 shared values are random bytes from memory beyond the variable block. Freeing them may then result in a crash. I would suggest two things to solve this. First replace_program, when called from a blueprint, should set the blueprint pointer of the replaced program to NULL, because then the blueprint won't be a blueprint for this program anymore. Second init_object_variables should copy the variables from the template given to clone_object and not necessarily from prog->blueprint. The second proposal may break things (especially when cloning from a clone, there it is now expected, that the variables are taken from the blueprint), but I think it's more intuitive. Changing this behaviour only in the case, when the template is not a clone, seems a half-hearted solution to me. And this change will allow applications as Fiona described in her Mail <Pine.LNX.4.33.0509231010370.16774-100000@hasyl03.desy.de> from September, 23rd 2005 on the LDMud-Talk list (for a specific weapon inherit a generic weapon, set some global variables like the weapon type and strength, do a replace_program and let others clone then this specific weapon). It would also avoid the "Can't initialize object 'obj/xyz#123': no blueprint." errors, when the inherit (i/y in this case) was destroyed meanwhile (which can happen very easily). Greetings, Gnomi.  | ||||
| Tags | No tags attached. | ||||
| Attached Files |  sharedvars.diff (3,512 bytes)   
 
Index: src/object.c
===================================================================
--- src/object.c	(Revision 2312)
+++ src/object.c	(Arbeitskopie)
@@ -448,7 +448,7 @@
 
 /*-------------------------------------------------------------------------*/
 void
-init_object_variables (object_t *ob)
+init_object_variables (object_t *ob, object_t *templ)
 
 /* The variables of object <ob> are initialized.
  * First, if <ob> is a clone, all variables marked as !VAR_INITIALIZED are
@@ -463,20 +463,14 @@
     /* For clones, copy the shared variable values */
     if ((ob->flags & O_CLONE))
     {
-        object_t *bp;
         int i;
         variable_t *p_vars;
         svalue_t *ob_vars, *bp_vars;
 
-        bp = ob->prog->blueprint;
-        if (!bp || bp->flags & O_DESTRUCTED)
-        {
-            if (bp) free_object(bp, "init_object_variables");
-            ob->prog->blueprint = NULL;
+        if (!templ || templ->flags & O_DESTRUCTED)
             bp_vars = NULL;
-        }
         else
-            bp_vars = bp->variables;
+            bp_vars = templ->variables;
 
         ob_vars = ob->variables;
         p_vars = ob->prog->variables;
@@ -1065,6 +1059,16 @@
             r_ob->ob->variables = new_vars;
         } /* if (change in vars) */
 
+        /* If this is a blueprint object, NULL out the pointer in the program,
+         * because this isn't the blueprint for this program anymore.
+         */
+        if (r_ob->ob->prog->blueprint == r_ob->ob)
+        {
+            r_ob->ob->prog->blueprint = NULL;
+            remove_prog_swap(r_ob->ob->prog, MY_TRUE);
+            free_object(r_ob->ob, "replace_programs: blueprint reference");
+        }
+        
         /* Replace the old program with the new one */
         old_prog = r_ob->ob->prog;
         r_ob->new_prog->ref++;
Index: src/object.h
===================================================================
--- src/object.h	(Revision 2312)
+++ src/object.h	(Arbeitskopie)
@@ -295,7 +295,7 @@
 extern void dealloc_object(object_t *, const char * file, int line);
 #endif
 extern object_t *get_empty_object(int num_var);
-extern void      init_object_variables (object_t *ob);
+extern void      init_object_variables (object_t *ob, object_t *templ);
 
 extern svalue_t *v_function_exists(svalue_t *sp, int num_arg);
 extern svalue_t *f_functionlist(svalue_t *sp);
Index: src/simulate.c
===================================================================
--- src/simulate.c	(Revision 2312)
+++ src/simulate.c	(Arbeitskopie)
@@ -2117,7 +2117,7 @@
         {
             /* The master object is loaded with no current object */
             current_object = NULL;
-            init_object_variables(ob);
+            init_object_variables(ob, NULL);
             reset_object(ob, create_super ? H_CREATE_SUPER : H_CREATE_OB);
 
             /* If the master inherits anything -Ugh- we have to have
@@ -2128,7 +2128,7 @@
         else
         {
             current_object = save_current;
-            init_object_variables(ob);
+            init_object_variables(ob, NULL);
             reset_object(ob, create_super ? H_CREATE_SUPER : H_CREATE_OB);
         }
     }
@@ -2337,7 +2337,7 @@
     push_ref_object(inter_sp, ob, "clone_object");
     push_ref_string(inter_sp, new_ob->name);
     give_uid_to_object(new_ob, H_CLONE_UIDS, 2);
-    init_object_variables(new_ob);
+    init_object_variables(new_ob, ob);
     reset_object(new_ob, H_CREATE_CLONE);
     command_giver = check_object(save_command_giver);
 
 | ||||
| Date Modified | Username | Field | Change | 
|---|---|---|---|
| 2006-08-10 05:44 | Gnomi | New Issue | |
| 2006-09-11 13:25 | Gnomi | File Added: sharedvars.diff | |
| 2006-09-11 13:27 | Gnomi | Note Added: 0000516 | |
| 2007-10-06 21:28 | 
					 | 
				Status | new => resolved | 
| 2007-10-06 21:28 | 
					 | 
				Fixed in Version | => 3.3.716 | 
| 2007-10-06 21:28 | 
					 | 
				Resolution | open => fixed | 
| 2007-10-06 21:28 | 
					 | 
				Assigned To | => lars | 
| 2007-10-06 21:28 | 
					 | 
				Note Added: 0000556 | |
| 2010-11-16 09:42 | 
					 | 
				Source_changeset_attached | => ldmud.git master 9e3fef8b | 
| 2018-01-29 18:59 | 
					 | 
				Source_changeset_attached | => ldmud.git master 9e3fef8b | 
| 2018-01-29 21:57 | 
					 | 
				Source_changeset_attached | => ldmud.git master 9e3fef8b |