In article <. com>
<> wrote:
> My program crashes on Linux64 platform.
In theory, the platform should not matter. In practice, since your
code uses undefined (by the standard) behavior, it does.
For discussion purposes, then, I will leave the above in, and add
another two notes:
- On your machine, pointers (regardless of the pointed-to type)
are 64 bits wide.
- On your machine, "int" is 32 bits wide.
>The crash only happens on optimized compiling, if I compile the
>code in debug mode, it works fine.
This is basically a matter of luck -- bad luck that it works at
all, good luck that it fails sometimes, and bad luck that the
failure occurs in the harder-to-debug version.
> In tracking the issue, I finally narrow the code into something like
>this:
"Something like" is dangerous -- it is usually best to show the
actual failing code. (In this case, that may not be possible; and
there was enough information here, fortunately.)
> int my_func(ClientData client_data,
> Tcl_Interp* interp,
> Tcl_Obj* CONST argv[]) {
>
> < some code >
>
> MyClass* myobj;
Note that "myobj" has type "pointer to MyClass", where "MyClass"
is presumably a typedef-alias for some other type. Since, on this
particular machine, all pointers are 64 bits, "myobj" is itself 64
bits wide. The 64 bits are not initialized, and hence may be full
of apparently-random trash (although if you are un?lucky, they may
be all-zeros or otherwise consistent).
> Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);
Here, the third argument to Tcl_GetIntFromObj() is the value of
the address of "myobj", but converted to "int *". In other words,
this "int *" -- which, at least logically speaking, ought to point
to an "int", which would be 32 bits wide -- actually points to a
"MyClass *", which is actually 64 bits wide.
The fact that you use (and need) a cast here is a very bad sign.
Next, you have parts of Tcl_GetIntFromObj() here:
>int
>Tcl_GetIntFromObj(interp, objPtr, intPtr)
> Tcl_Interp *interp; /* Used for error reporting if not NULL. */
> register Tcl_Obj *objPtr; /* The object from which to get a int. */
> register int *intPtr; /* Place to store resulting int. */
>{
>
> < some code>
>
> *intPtr = (int)w; <=== This is the only place intPtr is used
So Tcl_GetIntFromObj() really does set the 32 bits at *intPtr to
some 32-bit "int" value.
Since the actual object ("myobj") is 64 bits, whatever this does
is clearly not right. You need to set all 64 bits.
> I tested changing the code to:
>
> MyClass* myobj = NULL;
> Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);
>
> Now it works.
Well, that too is luck (but is it "good luck" or "bad luck"?).
Now you have initialized all 64 bits of "myobj", then changed 32
of the 64. The result might sometimes be correct, but is probably
wrong at least sometimes, if not often.
A correct *call* to Tcl_GetIntFromObj() should not need a cast.
For instance, if you really do want to get an "int":
int tmp;
...
Tcl_GetIntFromObj(interp, argv[1], &tmp);
If that "int" can then be somehow transformed into a pointer --
exactly how, I do not know; that is up to you -- you can then
do that:
MyClass *convert_int_to_obj(int);
MyClass *myobj;
int tmp;
...
Tcl_GetIntFromObj(interp, argv[1], &tmp);
myobj = convert_int_to_obj(tmp);
Note that this code contains no casts. (It still ignores the
"int" return value from Tcl_GetIntFromObj(), though.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.