#5108 Segmentation fault on linux 64 bit

obsolete: 8.5.12
closed-invalid
Jan Nijtmans
None
5
2012-09-07
2012-09-07
TobiasV
No

Hi,

We believe we have found a bug in the code for 64 bit system.

Our code that causes it is:
int socketfd;
if (Tcl_GetChannelHandle(channel, TCL_READABLE, (ClientData)&socketfd) != TCL_OK) {
return TCL_ERROR;
}

The cause is in:
In Tcl_GetChannelHandle() (tclIO.c)

ClientData handle;
result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData,
direction, &handle);
if (handlePtr) {
*handlePtr = handle;
}

and
tclUnixChan.c

static int
TcpGetHandleProc(
ClientData instanceData, /* The socket state. */
int direction, /* Not used. */
ClientData *handlePtr) /* Where to store the handle. */
{
TcpState *statePtr = (TcpState *) instanceData;

*handlePtr = (ClientData) INT2PTR(statePtr->fd);
return TCL_OK;
}

where it in the end tries to set *handlePtr (pointer to an int) to a long value.

And the solution should be:

Solution:

In Tcl_GetChannelHandle() (tclIO.c)

result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData,
direction, handlePtr);

In TcpGetHandleProc (tclUnixChan.c)

tclUnixChan.c

static int
TcpGetHandleProc(
ClientData instanceData, /* The socket state. */
int direction, /* Not used. */
ClientData *handlePtr) /* Where to store the handle. */
{
TcpState *statePtr = (TcpState *) instanceData;

if (handlePtr) {
*handlePtr = statePtr->fd;
}
return TCL_OK;
}

System information:
System information:
% parray tcl_platform
tcl_platform(byteOrder) = littleEndian
tcl_platform(machine) = x86_64
tcl_platform(os) = Linux
tcl_platform(osVersion) = 2.6.32.29-0.3-default
tcl_platform(platform) = unix
tcl_platform(pointerSize) = 8
tcl_platform(user) = xxxxx
tcl_platform(wordSize) = 8

Discussion

  • Jan Nijtmans
    Jan Nijtmans
    2012-09-07

    > int socketfd;
    > if (Tcl_GetChannelHandle(channel, TCL_READABLE, (ClientData)&socketfd) != TCL_OK) {
    > return TCL_ERROR;
    > }
    Casting a pointer to ClientData hides the compiler error that would
    have been generated otherwise. It's not safe to do something
    like that. Tcl_GetChannelHandle() is documented to return
    ClientData, not an int. Your code should look like:
    ClientData socketfd;
    if (Tcl_GetChannelHandle(channel, TCL_READABLE, &socketfd) != TCL_OK) {
    return TCL_ERROR;
    }
    So, I'm sorry to say it, but it's definitely not a Tcl bug.

     
  • Jan Nijtmans
    Jan Nijtmans
    2012-09-07

    • assigned_to: nobody --> nijtmans
    • status: open --> closed-invalid
     
  • I'd have expected to use INT2PTR(socketfd) in this case instead of (ClientData)&socketfd as the latter will point off into no-mans-land once its stack frame goes away. Unix FDs are "small" integers (they usually fit in a 'short', even on 64-bit systems) but the API takes a ClientData because that's needed on other platforms.