Tcl Source Code

View Ticket
Login
Ticket UUID: 801467
Title: incompatible memory debugging options...
Type: Bug Version: None
Submitter: mistachkin Created on: 2003-09-06 01:23:26
Subsystem: 41. Memory Allocation Assigned To: patthoyts
Priority: 9 Immediate Severity:
Status: Closed Last Modified: 2003-10-14 22:37:27
Resolution: Accepted Closed By: patthoyts
    Closed on: 2003-10-14 15:37:27
Description:
Copied from Tk bug #800419 at dgp's request.

Experiencing many crashes and test failures... 

Here is an example stack trace:

Tcl_PanicVA(const char * 0x100cd344, char * 
0x0012a42c) line 97 + 42 bytes
Tcl_Panic(const char * 0x100cd344) line 134 + 13 bytes
TclDbInitNewObj(Tcl_Obj * 0x00ad51d0) line 540 + 10 
bytes
Tcl_DbNewStringObj(const char * 0x009a4198, int 62, 
const char * 0x100b8348, int 4618) line 267 + 45 bytes
Tcl_AddObjErrorInfo(Tcl_Interp * 0x0086ade8, const 
char * 0x0012a468, int -1) line 4618 + 25 bytes
Tcl_LogCommandInfo(Tcl_Interp * 0x0086ade8, const 
char * 0x00af57d8, const char * 0x00af5d14, int 38) 
line 3325 + 18 bytes
TclExecuteByteCode(Tcl_Interp * 0x0086ade8, 
ByteCode * 0x00aba320) line 4134 + 27 bytes
TclCompEvalObj(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00add9a8) line 986 + 13 bytes
TclObjInterpProc(void * 0x00af0548, Tcl_Interp * 
0x0086ade8, int 1, Tcl_Obj * const * 0x0012b29c) line 
1080 + 19 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 1, 
Tcl_Obj * const * 0x0012b29c, const char * 
0x00ab8d57, int 13, int 0) line 3095 + 25 bytes
Tcl_EvalEx(Tcl_Interp * 0x0086ade8, const char * 
0x00ab5b58, int 12812, int 0) line 3525 + 36 bytes
Tcl_FSEvalFile(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a8dbe8) line 1445 + 19 bytes
Tcl_SourceObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 2, Tcl_Obj * const * 0x0012b654) line 
1012 + 16 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 2, 
Tcl_Obj * const * 0x0012b654, const char * 
0x00aa5070, int 56, int 0) line 3095 + 25 bytes
Tcl_EvalEx(Tcl_Interp * 0x0086ade8, const char * 
0x00aa5070, int 56, int 0) line 3525 + 36 bytes
Tcl_Eval(Tcl_Interp * 0x0086ade8, const char * 
0x00aa5070) line 3629 + 17 bytes
Tcl_GlobalEval(Tcl_Interp * 0x0086ade8, const char * 
0x00aa5070) line 4756 + 13 bytes
Tcl_PkgRequireEx(Tcl_Interp * 0x0086ade8, const char 
* 0x00a67608, const char * 0x00000000, int 0, void * * 
0x00000000) line 312 + 16 bytes
Tcl_PkgRequire(Tcl_Interp * 0x0086ade8, const char * 
0x00a67608, const char * 0x00000000, int 0) line 164 + 
23 bytes
Tcl_PackageObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 3, Tcl_Obj * const * 0x009800dc) line 
718 + 21 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 3, 
Tcl_Obj * const * 0x009800dc, const char * 
0x00000000, int 0, int 0) line 3095 + 25 bytes
TclExecuteByteCode(Tcl_Interp * 0x0086ade8, 
ByteCode * 0x00a35868) line 1407 + 36 bytes
TclCompEvalObj(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a29590) line 986 + 13 bytes
Tcl_EvalObjEx(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a29590, int 0) line 3759 + 13 bytes
NamespaceEvalCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 4, Tcl_Obj * const * 0x009800c8) line 
2976 + 18 bytes
Tcl_NamespaceObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 4, Tcl_Obj * const * 0x009800c8) line 
2529 + 21 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 4, 
Tcl_Obj * const * 0x009800c8, const char * 
0x00000000, int 0, int 0) line 3095 + 25 bytes
TclExecuteByteCode(Tcl_Interp * 0x0086ade8, 
ByteCode * 0x00a1e0b8) line 1407 + 36 bytes
TclCompEvalObj(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a81c10) line 986 + 13 bytes
Tcl_EvalObjEx(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a81c10, int 0) line 3759 + 13 bytes
NamespaceEvalCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 4, Tcl_Obj * const * 0x0012cf30) line 
2976 + 18 bytes
Tcl_NamespaceObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 4, Tcl_Obj * const * 0x0012cf30) line 
2529 + 21 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 4, 
Tcl_Obj * const * 0x0012cf30, const char * 
0x00a90246, int 982, int 0) line 3095 + 25 bytes
Tcl_EvalEx(Tcl_Interp * 0x0086ade8, const char * 
0x00a8ffb0, int 17577, int 0) line 3525 + 36 bytes
Tcl_FSEvalFile(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a81190) line 1445 + 19 bytes
Tcl_SourceObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 2, Tcl_Obj * const * 0x00a67708) line 
1012 + 16 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 2, 
Tcl_Obj * const * 0x00a67708, const char * 
0x100da7da, int 0, int 262144) line 3095 + 25 bytes
Tcl_EvalObjv(Tcl_Interp * 0x0086ade8, int 2, Tcl_Obj * 
const * 0x00a67708, int 262144) line 3206 + 32 bytes
Tcl_EvalObjEx(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a81f90, int 262144) line 3744 + 27 bytes
Tcl_UplevelObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 1, Tcl_Obj * const * 0x009800c4) line 
674 + 20 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 3, 
Tcl_Obj * const * 0x009800bc, const char * 
0x00000000, int 0, int 0) line 3095 + 25 bytes
TclExecuteByteCode(Tcl_Interp * 0x0086ade8, 
ByteCode * 0x00a80090) line 1407 + 36 bytes
TclCompEvalObj(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x00a6c610) line 986 + 13 bytes
TclObjInterpProc(void * 0x00a62c00, Tcl_Interp * 
0x0086ade8, int 7, Tcl_Obj * const * 0x00a22d00) line 
1080 + 19 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 7, 
Tcl_Obj * const * 0x00a22d00, const char * 
0x100da7da, int 0, int 262144) line 3095 + 25 bytes
Tcl_EvalObjv(Tcl_Interp * 0x0086ade8, int 7, Tcl_Obj * 
const * 0x00a22d00, int 262144) line 3206 + 32 bytes
Tcl_EvalObjEx(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x009c7588, int 262144) line 3744 + 27 bytes
Tcl_UplevelObjCmd(void * 0x00000000, Tcl_Interp * 
0x0086ade8, int 1, Tcl_Obj * const * 0x009800b8) line 
674 + 20 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 3, 
Tcl_Obj * const * 0x009800b0, const char * 
0x00000000, int 0, int 0) line 3095 + 25 bytes
TclExecuteByteCode(Tcl_Interp * 0x0086ade8, 
ByteCode * 0x00a3b430) line 1407 + 36 bytes
TclCompEvalObj(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x009c7f88) line 986 + 13 bytes
TclObjInterpProc(void * 0x009c7f08, Tcl_Interp * 
0x0086ade8, int 8, Tcl_Obj * const * 0x00a29790) line 
1080 + 19 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 8, 
Tcl_Obj * const * 0x00a29790, const char * 
0x00000000, int 0, int 0) line 3095 + 25 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 7, 
Tcl_Obj * const * 0x00980094, const char * 
0x00000000, int 0, int 0) line 3047 + 30 bytes
TclExecuteByteCode(Tcl_Interp * 0x0086ade8, 
ByteCode * 0x00a17c28) line 1407 + 36 bytes
TclCompEvalObj(Tcl_Interp * 0x0086ade8, Tcl_Obj * 
0x009991c0) line 986 + 13 bytes
TclObjInterpProc(void * 0x0099e308, Tcl_Interp * 
0x0086ade8, int 1, Tcl_Obj * const * 0x0012f9e4) line 
1080 + 19 bytes
TclEvalObjvInternal(Tcl_Interp * 0x0086ade8, int 1, 
Tcl_Obj * const * 0x0012f9e4, const char * 
0x002f333c, int 6, int 0) line 3095 + 25 bytes
Tcl_EvalEx(Tcl_Interp * 0x0086ade8, const char * 
0x002f3270 initScript, int 210, int 0) line 3525 + 36 bytes
Tcl_Eval(Tcl_Interp * 0x0086ade8, const char * 
0x002f3270 initScript) line 3629 + 17 bytes
TkpInit(Tcl_Interp * 0x0086ade8) line 51 + 21 bytes
Initialize(Tcl_Interp * 0x0086ade8) line 3164 + 9 bytes
Tk_Init(Tcl_Interp * 0x0086ade8) line 2804 + 9 bytes
Tcl_AppInit(Tcl_Interp * 0x0086ade8) line 161 + 10 
bytes
Tk_MainEx(int 1, char * * 0x00866e20, int (Tcl_Interp *)
* 0x004010b9 Tcl_AppInit(Tcl_Interp *), Tcl_Interp * 
0x0086ade8) line 222 + 7 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 
0x00000000, char * 0x0013374d, int 1) line 130 + 26 
bytes
WinMainCRTStartup() line 330 + 54 bytes

----

More analysis reveals the following additional diagnostics 
(tailored for this particular bug):

ADD, obj = 0x00ADB540, hPtr = 0x009B3730, file 
= ..\generic\tclResult.c, line = 828
MARK DELETE, obj = 0x00ADB540, hPtr = 0x009B3730, 
file 
= ..\generic\tclExecute.c, line = 1182
DELETE, obj = 0x00ADB540, file 
= ..\generic\tclExecute.c, line 
= 1182
ADD, obj = 0x00ADB540, hPtr = 0x009B3730, file 
= ..\generic\tclExecute.c, line = 1287
MARK DELETE, obj = 0x00ADB540, hPtr = 0x009B3730, 
file 
= ..\generic\tclExecute.c, line = 1153
DELETE, obj = 0x00ADB540, file 
= ..\generic\tclExecute.c, line 
= 1153
ADD, obj = 0x00ADB540, hPtr = 0x00ADB040, file = 
unknown, 
line = 0
ADD (PANIC), obj = 0x00ADB540, hPtr = 0x00ADB040, file 
= ..\generic\tclBasic.c, line = 4618

As we can see from the above, something (apparently) 
outside the normal channels (the 'file == "unknown"'
line) is
responsible for adding this objPtr handle and never 
removing it 
from the hash table.  However, Tcl_DbCkalloc (really the 
threaded memory allocator) thinks (probably rightly) that 
the 
actual BLOCK of memory is free.

----

After a bit of research, I found the offending code 
(where the objPtr is allocated first):

rootObj = Tcl_NewStringObj(rootName, -1);

tclWinReg.c, line 1086

Either this object is being allocated using the wrong 
function 
(?) or this object is being freed using the wrong function 
(TclFreeObj versus Tcl_DbDecrRefCount), because the 
hash 
entry remains after the block is freed.

Additionally, the object never has it's refcount 
incremented 
after it is allocated.

I *think* I have come to the conclusion 
that "tcl/win/makefile.vc" is at fault for this problem.
tclWinReg.c (and possibly other files) are NOT being 
compiled 
with TCL_CFLAGS (including TCL_MEM_DEBUG).

Unless I'm wrong, this could indicate a much bigger 
problem 
with the way extensions interact with Tcl's memory 
allocation 
and debugging facilities.

If an extension compiled without TCL_MEM_DEBUG calls 
Tcl_NewStringObj in a TCL_MEM_DEBUG enabled tcl.dll 
(which 
apparently ALWAYS adds the new objptr to the hash 
table) 
and then uses the non-debug Tcl_DecrRefCount 
__macro__ 
from tcl.h, major breakage like this bug could occur.

Attaching a patch to correct the problem.
User Comments: patthoyts added on 2003-10-14 22:37:27:
Logged In: YES 
user_id=202636

Committed both patches to Tk as well.

hobbs added on 2003-10-13 06:26:21:
Logged In: YES 
user_id=72656

assigning to pat since he's halfway done already

patthoyts added on 2003-10-09 07:28:30:
Logged In: YES 
user_id=202636

I have tested the tcl patches here against the HEAD. With
OPTS=symbols,threads and STATS=memdbg the unpatched tcl will
crash horribly on the registry.test and when patched it runs
fine.

Applied to tcl 8.5 HEAD

Tk next.

mistachkin added on 2003-10-04 06:18:07:
Logged In: YES 
user_id=113501

Please note that I believe this bug (perhaps not the actual 
panic) is also present in the core-8-4-branch.  The root of 
the problem is incompatible debug flags between tclsh/wish 
and the registry/dde packages (which never get the debug 
flags without the attached fix).

dkf added on 2003-09-29 17:23:15:
Logged In: YES 
user_id=79902

New fields *MUST NOT* be introduced into the middle of the
Tcl_Obj structure under any circumstances without a major
version number change because it runs utterly roughshod over
stubs compatability.  We also do not wish to have the size
of Tcl_Obj (or any other public structure) change between
debug and non-debug builds as that makes memory debugging
much more difficult. Also remember that on many platforms, a
debugging extension may be successfully loaded into a
non-debugging core (or the other way round.)

mistachkin added on 2003-09-25 21:25:30:
Logged In: YES 
user_id=113501

I'm pretty sure that the fields MUST be before the internal 
rep, as it is variable size (?).

dkf added on 2003-09-11 22:47:40:
Logged In: YES 
user_id=79902

Erk!  *After* at the very lease!  Don't change the positions
of fields between non-debug and debug builds...

mistachkin added on 2003-09-06 12:23:54:

File Added - 60787: tk_bugfix_801467.diff.zip

mistachkin added on 2003-09-06 12:21:07:

File Added - 60786: tcl_bugfix_801467.diff.zip

mistachkin added on 2003-09-06 12:01:37:

File Added - 60785: tk_appinit.diff.zip

mistachkin added on 2003-09-06 10:50:56:
Logged In: YES 
user_id=113501

Another very useful thing to have would be the following 
fields right before the internal rep in the Tcl_Obj struct (only 
when TCL_MEM_DEBUG is enabled):

#ifdef TCL_MEM_DEBUG
    CONST char *file;     /* Source file where originally 
allocated. */
    int line;                   /* Source line where originally 
allocated. */
#endif

These can be set from inside TclDbInitNewObj, if 
TclDbInitNewObj is changed according to Tcl feature request 
#800925.

mistachkin added on 2003-09-06 09:31:42:

File Deleted - 60761: 

Logged In: YES 
user_id=113501

after more testing, still seeing some problems here, removing 
the patch.

mistachkin added on 2003-09-06 08:28:29:

File Added - 60762: tcl_appinit.diff.zip

Logged In: YES 
user_id=113501

All the attached patches are related and should be applied.

mistachkin added on 2003-09-06 08:23:26:

File Added - 60761: makefile.diff.zip

Attachments: