By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,116 Members | 1,097 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,116 IT Pros & Developers. It's quick & easy.

Why this fix work ?

P: n/a
Hi,
My program crashes on Linux64 platform. The crash only happens on
optimized compiling, if I compile the code in debug mode, it works
fine. If I compile the code on Linux 32 platform, neither debug mode
nor optimized mode crashes.

In tracking the issue, I finally narrow the code into something like
this:

int my_func(ClientData client_data,
Tcl_Interp* interp,
Tcl_Obj* CONST argv[]) {

< some code >

MyClass* myobj;
Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);
You can see this is to interact with TCL through C/TCL interface,
you can also see that myobj is not initialized before used.

I tested changing the code to:

MyClass* myobj = NULL;
Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);

Now it works.

But this does not make sense to me. I check into TCL 8.4 source code
for this function, Tcl_GetIntFromObj(), the simplified version is like
this,

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
return TCL_OK;
}

I do not see why my change, give myobj an initial assignment, could
make difference upon this TCL code except the following 2
obsersavations:

1. If I do not assign myobj to NULL, compiler may give it a wild
address which in optimized mode always points to some not-allowed
address?

2. The TCL function declares the argument as "register int *intPtr",
I never use "register" keyword in my C programming, not sure if it has
a role over here.

Would really appreciate if you could shed some light here.

Jun 19 '07 #1
Share this Question
Share on Google+
13 Replies


P: n/a
In article <11*********************@z28g2000prd.googlegroups. com>,
<li*****@hotmail.comwrote:
My program crashes on Linux64 platform. The crash only happens on
optimized compiling, if I compile the code in debug mode, it works
fine. If I compile the code on Linux 32 platform, neither debug mode
nor optimized mode crashes.
MyClass* myobj;
Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);
But this does not make sense to me. I check into TCL 8.4 source code
for this function, Tcl_GetIntFromObj(), the simplified version is like
this,
>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. */
{
*intPtr = (int)w; <=== This is the only place intPtr is used
You are writing an object the width of an int into an object defined
to be the width of a pointer (MyClass* myobj). Possibly your int
is wider than your pointer ?
--
Okay, buzzwords only. Two syllables, tops. -- Laurie Anderson
Jun 20 '07 #2

P: n/a
Walter Roberson wrote:
In article <11*********************@z28g2000prd.googlegroups. com>,
<li*****@hotmail.comwrote:
> My program crashes on Linux64 platform. The crash only happens on
optimized compiling, if I compile the code in debug mode, it works
fine. If I compile the code on Linux 32 platform, neither debug mode
nor optimized mode crashes.
> MyClass* myobj;
Tcl_GetIntFromObj(interp, argv[1], (int *) &myobj);
> But this does not make sense to me. I check into TCL 8.4 source code
for this function, Tcl_GetIntFromObj(), the simplified version is like
this,
>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. */
{

> *intPtr = (int)w; <=== This is the only place intPtr is used

You are writing an object the width of an int into an object defined
to be the width of a pointer (MyClass* myobj). Possibly your int
is wider than your pointer ?
More likely the other way round, writing say a 32 bit int into a 64 bit
pointer, leaving half of the bits untouched. Initialising the pointer
to all bits zero clears these bits, yielding a different value after the
function call.

--
Ian Collins.
Jun 20 '07 #3

P: n/a
In article <11*********************@z28g2000prd.googlegroups. com>
<li*****@hotmail.comwrote:
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 (4039.22'N, 11150.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.
Jun 20 '07 #4

P: n/a
I replied earlier through groups.google, but do not see it, so I post
again. Please scroll to the bottom.
On Jun 19, 7:39 pm, Chris Torek <nos...@torek.netwrote:
In article <1182296273.993929.15...@z28g2000prd.googlegroups. com>

<linq...@hotmail.comwrote:
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 (4039.22'N, 11150.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 spam
Chris,
There is no word I can express my appreciation.

Thank you!

Your suggestion makes sense to me, but one thing I do not quite get.

I initialize the pointer to 0 :

MyClass* myobj = NULL;

This is means all 64 bits are '\0' now, later when it is assigned with
a 32 bit data, it is only the least significant 32 bits are updated
and the the other 32 bit keep 0. If this is correct, then there is no
potential problem here. Why do you say " The result might sometimes be
correct, but is probably wrong at least sometimes"? As I see, it
should always be right.

I tested the following code on 32 bit Linux machine:

#include <stdio.h>

void func(unsigned char* cp){
*cp = 255;
}

int main(){
unsigned int i = 0x80000000;
printf("before func(), i=0x%x.\n", i);
func( (unsigned char*) &i );
printf("after func(), i=0x%x.\n", i);

return 0;
}

And the print out is as expected:

before func(), i=0x80000000.
after func(), i=0x800000ff.
Looking forward to your further teaching.

Jun 20 '07 #5

P: n/a
li*****@hotmail.com wrote:
On Jun 19, 7:39 pm, Chris Torek <nos...@torek.netwrote:
>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.)

Chris,
There is no word I can express my appreciation.

Thank you!

Your suggestion makes sense to me, but one thing I do not quite get.

I initialize the pointer to 0 :

MyClass* myobj = NULL;

This is means all 64 bits are '\0' now, later when it is assigned with
a 32 bit data, it is only the least significant 32 bits are updated
and the the other 32 bit keep 0. If this is correct, then there is no
potential problem here. Why do you say " The result might sometimes be
correct, but is probably wrong at least sometimes"? As I see, it
should always be right.
What happens on a system where a 64 bit pointer has something other that
all bits zero in the bits that you are not writing?

You should follow Chris' advice and make the code "clean" without the
casts, which may be hiding something nasty. If this proves difficult,
you are doing something wrong.

--
Ian Collins.
Jun 20 '07 #6

P: n/a
On Jun 19, 11:38 pm, Ian Collins <ian-n...@hotmail.comwrote:
linq...@hotmail.com wrote:
On Jun 19, 7:39 pm, Chris Torek <nos...@torek.netwrote:
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.)
Chris,
There is no word I can express my appreciation.
Thank you!
Your suggestion makes sense to me, but one thing I do not quite get.
I initialize the pointer to 0 :
MyClass* myobj = NULL;
This is means all 64 bits are '\0' now, later when it is assigned with
a 32 bit data, it is only the least significant 32 bits are updated
and the the other 32 bit keep 0. If this is correct, then there is no
potential problem here. Why do you say " The result might sometimes be
correct, but is probably wrong at least sometimes"? As I see, it
should always be right.

What happens on a system where a 64 bit pointer has something other that
all bits zero in the bits that you are not writing?

You should follow Chris' advice and make the code "clean" without the
casts, which may be hiding something nasty. If this proves difficult,
you are doing something wrong.

--
Ian Collins.
I need more clarification here, let us translate the code into another
presentation:
MyClass* myobj = NULL; ==myobj = 0x00000000_00000000
<during that TCL function call ==myobj = 0x00000000_########

So basically what you and Chris say is that after the TCL function
call, the first 32 bit of myobj might not be all zero? How come? Is
this compiler dependent?

2nd question is about C/TCL communication. MyClass is a struct type
which includes pretty complex data. Basically I have TCL script to
define the data and return it back to C. The protocol between C and
TCL is that, the data is in memory, the interface passes an integer
pointer to C code, that pointer points to the memory location of the
data defined in the memory, and user C code casts the integer pointer
as the corresponding type pointer.

It seems to me the whole point of you and Chris is that cast because
we can do nothing on how TCL passes memory pointer to C and because of
the inequality of 32 bit and 64 bit, we must make sure the extra 32
bit must be zero, then does the following descriptive code make sense:

MyClass *convert_int_to_obj(int i){
int my_type_size = sizeof(MyClass*);
int int_size = sizeof(i);
int total_bit_diff = ( my_type_size - int_size) * 8;

MyClass* ptr = NULL;
(&ptr) = i; <== this may not be compiler allowed, just for
description

for ( int j=0; j<total_bit_diff; j++ ){
< assign ptr's the most significant bits to sero>
}

return ptr;
}

Jun 20 '07 #7

P: n/a
In article <11**********************@o11g2000prd.googlegroups .com>,
<li*****@hotmail.comwrote:
>I need more clarification here, let us translate the code into another
presentation:
MyClass* myobj = NULL; ==myobj = 0x00000000_00000000
<during that TCL function call ==myobj = 0x00000000_########
>So basically what you and Chris say is that after the TCL function
call, the first 32 bit of myobj might not be all zero? How come? Is
this compiler dependent?
There is an additional complication.

Suppose myobj is M bits wide, and an int is N bits wide, and for
now assume that M N. When you take the address of myobj and cast
that address to int* and write through that int*, you are writing
the N bits from the beginning of myobj, because C makes promises
about how addresses increase. But the N bits that are stored from
the beginning of myobj are not necessary the "most significant"
or even the "least significant" bits of myobj when myobj is
interpreted in its full M bits as another kind of value.

It is, for example, allowed that the byte order for an int (assuming
for a second that an int is two bytes) is 2 1 and that the byte order
for a long (assuming for a second that a long is four bytes) is 4 2 1 3,
so setting the first two bytes of the memory via an int could end up
setting the second and fourth bytes of the long, leaving the first
and third bytes of the long as whatever they had before (or leaving
it in a trap state if the OS micro-manages information about which
bytes have been initialized, which is possible.)

--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)
Jun 20 '07 #8

P: n/a
On Jun 20, 10:19 am, rober...@ibd.nrc-cnrc.gc.ca (Walter Roberson)
wrote:
In article <1182348735.573241.259...@o11g2000prd.googlegroups .com>,

<linq...@hotmail.comwrote:
I need more clarification here, let us translate the code into another
presentation:
MyClass* myobj = NULL; ==myobj = 0x00000000_00000000
<during that TCL function call ==myobj = 0x00000000_########
So basically what you and Chris say is that after the TCL function
call, the first 32 bit of myobj might not be all zero? How come? Is
this compiler dependent?

There is an additional complication.

Suppose myobj is M bits wide, and an int is N bits wide, and for
now assume that M N. When you take the address of myobj and cast
that address to int* and write through that int*, you are writing
the N bits from the beginning of myobj, because C makes promises
about how addresses increase. But the N bits that are stored from
the beginning of myobj are not necessary the "most significant"
or even the "least significant" bits of myobj when myobj is
interpreted in its full M bits as another kind of value.

It is, for example, allowed that the byte order for an int (assuming
for a second that an int is two bytes) is 2 1 and that the byte order
for a long (assuming for a second that a long is four bytes) is 4 2 1 3,
so setting the first two bytes of the memory via an int could end up
setting the second and fourth bytes of the long, leaving the first
and third bytes of the long as whatever they had before (or leaving
it in a trap state if the OS micro-manages information about which
bytes have been initialized, which is possible.)

--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)
Walter,
Thanks.

It is surprise to know the memory layout could be different as I
expected, but it is hard for me to imagine how this will work. For
example, let's say one integer is 2 byte in length and the layout is 2
1 and a long is 4 2 1 3. Then if I have the following code:

int i = 0x1001
long l = 0x10110001
char* p = &i; <== now p points to byte 2 of i which is 0x10?
p++; <== now p points to byte 1 of i which is 0x01?
char* p = &l; <== now p points to byte 4 of i which is 0x10?
p++; <== now p points to byte 2 of i which is 0x00?

I think I see code which uses smaller type pointer to access larger
type data, if the order is totally dependent on compiler/CPU
implementation, then such code is not portable. Is that right?

Anyway, i am even more confused what is the best way to write clean
code here. I gave an example code in my previous post to implement
convert_int_to_obj(), but if I can not assume safely the memory
layout, I can not think of that function implementation.

Any idea?
Jun 20 '07 #9

P: n/a
In article <11**********************@q19g2000prn.googlegroups .com>,
<li*****@hotmail.comwrote:
I think I see code which uses smaller type pointer to access larger
type data, if the order is totally dependent on compiler/CPU
implementation, then such code is not portable. Is that right?
Right. You can probe the ordering and make appropriate adjustments
by, for example, long T = 0x01020304; unsigned char *P = &T;
then P[0] tells you which value byte of T is stored at the lowest
address, P[1] tells you which value byte of T is stored at the
next address, and so on.

Anyway, i am even more confused what is the best way to write clean
code here. I gave an example code in my previous post to implement
convert_int_to_obj(), but if I can not assume safely the memory
layout, I can not think of that function implementation.
I haven't studied the thread in detail, but part of the problem
in the original code seemed to be that you were perhaps going
indirect one too many times. You had myobj as a pointer (value
uninitialized), and you were passing the -address- of myobj
down to the lower level, and setting what was at that pointer
to be an int. But what is at that pointer is the address (pointer) myobj,
not any storage for myobj. Your code would have made more
sense if you had had

SomeType *myobj = malloc(sizeof *myobj);
TCL_call( (int *)myobj );

then when TCL_call went indirect on the pointer and stored an int
there, the storage it would have been setting would have been the
malloc'd storage, not the pointer myobj.
--
If you lie to the compiler, it will get its revenge. -- Henry Spencer
Jun 20 '07 #10

P: n/a
>On Jun 19, 7:39 pm, Chris Torek <nos...@torek.netwrote:
>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.
[Snip the rest of the discussion, which amounts to: by playing games
with pointers, you wind up setting just 32 out of the 64 bits.]

In article <11**********************@d30g2000prg.googlegroups .com>
<li*****@hotmail.comwrote:
>[If] I initialize the pointer to 0 :

MyClass* myobj = NULL;

This is means all 64 bits are '\0' now, later when it is assigned with
a 32 bit data, it is only the least significant 32 bits are updated
and the the other 32 bit keep 0.
This is the case *on the given machine*. What happens on another
machine, where pointers are 32 bits, but "int" is 64 bits? In this
case, you will set 64 of the 32 bits.

Even if you never run into such a machine -- i.e., you stick with this
64-bit-pointer, 32-bit int system "forever" -- what happens if, well:
>If this is correct, then there is no potential problem here. Why do
you say " The result might sometimes be correct, but is probably
wrong at least sometimes"?
Suppose the *proper* pointer value is not 0x0000000012345678 (in
which the upper 32 bits are still all zero), but rather something
like 0x0000000112345678, in which you need more bits outside the
32-bit range? In other words, suppose you have "used up" the first
4 gigabytes of address-able space, and your program is now using
addresses in the 5-gigabyte-or-more range.

(Some 64-bit systems *start* your data space in addresses outside
the low 32 bits, although your particular version of your particular
OS does not.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.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.
Jun 20 '07 #11

P: n/a
li*****@hotmail.com writes:
[...]
I need more clarification here, let us translate the code into another
presentation:
MyClass* myobj = NULL; ==myobj = 0x00000000_00000000
There's no guarantee that a null pointer is represented as
all-bits-zero, though it probably is in most implementations. See
section 5 of the comp.lang.c FAQ, <http://www.c-faq.com/>.
<during that TCL function call ==myobj = 0x00000000_########

So basically what you and Chris say is that after the TCL function
call, the first 32 bit of myobj might not be all zero? How come? Is
this compiler dependent?
You're talking about modifying just 32 bits of a 64-bit pointer. I
hope you're not actually trying to do that.
2nd question is about C/TCL communication. MyClass is a struct type
which includes pretty complex data. Basically I have TCL script to
define the data and return it back to C. The protocol between C and
TCL is that, the data is in memory, the interface passes an integer
pointer to C code, that pointer points to the memory location of the
data defined in the memory, and user C code casts the integer pointer
as the corresponding type pointer.
What do you mean by "integer pointer"? You can have a pointer to an
integer, but you can't have anything that's both a pointer and an
integer. The language defines conversions between integer types and
pointer types, but the results are implementation-defined. There
*may* be an integer type big enough so that you an convert a pointer
to that integer type and back again without loss of information (if
so, it's intptr_t and/or uintptr_t in C99's <stdin.hheader), but
there may not be such a type at all.

If you have an interface that attempts to store pointer data in
integer values, that interface is broken. It might be possible to fix
the interface for your platform by using a sufficiently large integer
type, but even that's not guaranteed. (For example, suppose you have
32-bit int, 64-bit long, and 64-bit pointers. Storing a pointer in an
int will fail, but storing a pointer in a long might work. But the
*right* thing to do is to store pointers in pointers.)
It seems to me the whole point of you and Chris is that cast because
we can do nothing on how TCL passes memory pointer to C and because of
the inequality of 32 bit and 64 bit, we must make sure the extra 32
bit must be zero, then does the following descriptive code make sense:

MyClass *convert_int_to_obj(int i){
int my_type_size = sizeof(MyClass*);
int int_size = sizeof(i);
int total_bit_diff = ( my_type_size - int_size) * 8;

MyClass* ptr = NULL;
(&ptr) = i; <== this may not be compiler allowed, just for
description
"(&ptr) = i;" is illegal, and I'm not even sure what it's supposed to
mean. If you want to store the value of i in ptr, you can do
ptr = (MyClass*)i;
but the conversion can lose information.
for ( int j=0; j<total_bit_diff; j++ ){
< assign ptr's the most significant bits to sero>
}

return ptr;
}
I think what you're *trying* to do is:

Copy the value of i (an int) into the low-order 32 bits of ptr.
Set the high-order 32 bits of ptr to zero.

The result is very likely to be garbage. There just isn't enough
information in a 32-bit int to construct a valid 64-bit pointer. You
need to find another way to accomplish whatever it is you're trying to
do.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 20 '07 #12

P: n/a
On Wed, 20 Jun 2007 07:12:15 -0700, in comp.lang.c ,
li*****@hotmail.com wrote:
>I need more clarification here, let us translate the code into another
presentation:
MyClass* myobj = NULL; ==myobj = 0x00000000_00000000
><during that TCL function call ==myobj = 0x00000000_########
This is your problem and its a classic mistake that people make when
porting from one architecture to another, especially where pointer
sizes change.

You are assuming that the TCL function call only needs to return 32
bits. But what if the object it points to has an address which is more
than 32-bits wide? eg 0x01000000_######## - you have lost the first
32 bits when you copied it via an int. Disaster!!!

Moral: do not use casts to 'stop the compiler complaining'.
Moral 2: pointers are not ints.
>So basically what you and Chris say is that after the TCL function
call, the first 32 bit of myobj might not be all zero? How come? Is
this compiler dependent?
No, what they're saying is that they WILL be zero, and that could be
the wrong value.
>2nd question is about C/TCL communication. MyClass is a struct type
which includes pretty complex data. Basically I have TCL script to
define the data and return it back to C. The protocol between C and
TCL is that, the data is in memory, the interface passes an integer
pointer to C code,
If TCL is returning a 32-bit int and assuming a pointer will fit into
it, then it has a bug on the 64-bit platform, and you should complain
to the makers!

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jun 20 '07 #13

P: n/a
Walter Roberson wrote:
I haven't studied the thread in detail, but part of the problem
in the original code seemed to be that you were perhaps going
indirect one too many times. You had myobj as a pointer (value
uninitialized), and you were passing the -address- of myobj
down to the lower level, and setting what was at that pointer
to be an int. But what is at that pointer is the address (pointer) myobj,
not any storage for myobj. Your code would have made more
sense if you had had

SomeType *myobj = malloc(sizeof *myobj);
TCL_call( (int *)myobj );

then when TCL_call went indirect on the pointer and stored an int
there, the storage it would have been setting would have been the
malloc'd storage, not the pointer myobj.
Exactly what I think, a possible other solution would be:

SomeType myobj;
TCL_call( (int *)&myobj );
Jun 21 '07 #14

This discussion thread is closed

Replies have been disabled for this discussion.