Hi Donal,

 

Thank you for commenting at https://sourceforge.net/tracker2/index.php?func=detail&aid=1852572&group_id=10894&atid=110894

 

"Looking through NativeAccess() in tclWinFile.c, it seems that something
must be wrong in second stage of the function, which is where we are trying
to check the security access for the file. Though you could try using a
debugger to see which branches in that function it takes; that would be
very helpful to whoever ends up fixing this issue..."

 

I have the setup of samba server and tcl on Windows that shows the unexpected behavior of "file writable" .

 

So I setup MinGW, MSYS, and gdb on a Windows XP machine, downloaded tcl source code and built it.

$cd ~/build/tcl

$../../src/tcl8.5.6/win/configure --prefix=/opt/tcl --enable-symbol

$make

$make install

 

Now start gdb

 

$ gdb tclsh85g.exe

GNU gdb 5.2.1

Copyright 2002 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i686-pc-mingw32"...

(gdb) dll-symbol tcl85g.dll

(gdb) list NativeAccess

1538   

1539    static int

1540    NativeAccess(

1541        const TCHAR *nativePath,    /* Path of file to access, native encoding. */

1542        int mode)                   /* Permission setting. */

1543    {

1544        DWORD attr;

1545   

1546        attr = (*tclWinProcs->getFileAttributesProc)(nativePath);

1547   

(gdb)

 

I have stepped through in gdb the NativeAccess() function and the functions called it.   Please help to  check the log below and tell us where thing went wrong.

 

Please advice what else should I do in gdb to track down the bug.

 

 

Regards,

Danny Zeng

 

 

#

# now start gdb

#

$ gdb tclsh85g.exe

GNU gdb 5.2.1

Copyright 2002 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i686-pc-mingw32"...

(gdb) dll-symbol tcl85g.dll

(gdb) list NativeAccess

1538   

1539    static int

1540    NativeAccess(

1541        const TCHAR *nativePath,    /* Path of file to access, native encoding. */

1542        int mode)                   /* Permission setting. */

1543    {

1544        DWORD attr;

1545   

1546        attr = (*tclWinProcs->getFileAttributesProc)(nativePath);

1547   

(gdb)    break 1546

(gdb) run

#

# break reached and I played around

#

(gdb)    cont    

...

#

# now in tclsh I changed to the network drive and

# issued "file writable test.txt"

# where text.txt is a file I created and modified a few times

#

#

Breakpoint 1, NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1546

1546        attr = (*tclWinProcs->getFileAttributesProc)(nativePath);

(gdb) next

1548        if (attr == 0xffffffff) {

(gdb) print attr

$4 = 32

(gdb) info stack

#0  NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1548

#1  0x64e63b68 in TclpObjAccess (pathPtr=0xae2408, mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:2385

#2  0x64e12026 in Tcl_FSAccess (pathPtr=0xae2408, mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclIOUtil.c:2127

#3  0x64d9ea6c in CheckAccess (interp=0x3d7f48, pathPtr=0xae2408, mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclCmdAH.c:1409

#4  0x64d9e9f2 in Tcl_FileObjCmd (dummy=0x0, interp=0x3d7f48, objc=3,

    objv=0xa9d2b8)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclCmdAH.c:1370

#5  0x64d92e5d in TclEvalObjvInternal (interp=0x3d7f48, objc=3, objv=0xa9d2b8,

    command=0xffffffff "P~º", length=-1, flags=0)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclBasic.c:3690

#6  0x64de44a4 in TclExecuteByteCode (interp=0x3d7f48, codePtr=0xae5338)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclExecute.c:2340

#7  0x64de2a3f in TclCompEvalObj (interp=0x3d7f48, objPtr=0xae2450,

    invoker=0x0, word=0)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclExecute.c:1474

#8  0x64d949cc in TclEvalObjEx (interp=0x3d7f48, objPtr=0xae2450,

    flags=131072, invoker=0x0, word=0)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclBasic.c:5095

#9  0x64d94623 in Tcl_EvalObjEx (interp=0x3d7f48, objPtr=0xae2450,

    flags=131072) at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclBasic.c:4903

#10 0x64df9150 in Tcl_RecordAndEvalObj (interp=0x3d7f48, cmdPtr=0xae2450,

    flags=131072)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclHistory.c:161

#11 0x64e19f35 in Tcl_Main (argc=-1, argv=0x3d269c,

    appInitProc=0x401378 <Tcl_AppInit>)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclMain.c:554

#12 0x00401371 in main (argc=1, argv=0x3d2698)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclAppInit.c:102

(gdb)

(gdb) next

1557        if ((mode & W_OK)

(gdb)

1571        if (mode & X_OK) {

(gdb)

1594        if ((mode != F_OK) && (tclWinProcs->getFileSecurityProc != NULL)) {

(gdb)

1595            SECURITY_DESCRIPTOR *sdPtr = NULL;

(gdb)

1598            HANDLE hToken = NULL;

(gdb)

1599            DWORD desiredAccess = 0, grantedAccess = 0;

(gdb)

1600            BOOL accessYesNo = FALSE;

(gdb)

1602            DWORD privSetSize = sizeof(PRIVILEGE_SET);

(gdb)

1609            size = 0;

(gdb)

1610            (*tclWinProcs->getFileSecurityProc)(nativePath,

(gdb) 

0x77dfbcde in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

0x7c9140fd in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1618

1618            error = GetLastError();

(gdb) 

1619            if (error != ERROR_INSUFFICIENT_BUFFER) {

(gdb) print error

$5 = 122

(gdb)

(gdb) next

1633            sdPtr = (SECURITY_DESCRIPTOR *) HeapAlloc(GetProcessHeap(), 0, size);

(gdb)

1635            if (sdPtr == NULL) {

(gdb)

1643            if (!(*tclWinProcs->getFileSecurityProc)(nativePath,

(gdb)

0x77dfbcde in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

0x7c9140fd in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1658

1658            if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) {

(gdb)

0x77dfd203 in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

0x7c92aa7d in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1665

1665            if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread(),

(gdb)

0x77dd7b3d in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

0x7c90de0e in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1674

1674            (*tclWinProcs->revertToSelfProc)();

(gdb)

0x77dd7ba9 in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

0x7c90e642 in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1681

1681            if (mode & R_OK) {

(gdb)

(gdb) next

1684            if (mode & W_OK) {

(gdb)

1685                desiredAccess |= FILE_GENERIC_WRITE;

(gdb)

1687            if (mode & X_OK) {

(gdb)

1691            memset(&genMap, 0x0, sizeof(GENERIC_MAPPING));

(gdb)

1692            genMap.GenericRead = FILE_GENERIC_READ;

(gdb)

1693            genMap.GenericWrite = FILE_GENERIC_WRITE;

(gdb)

1694            genMap.GenericExecute = FILE_GENERIC_EXECUTE;

(gdb)

1695            genMap.GenericAll = FILE_ALL_ACCESS;

(gdb)

1701            if (!(*tclWinProcs->accessCheckProc)(sdPtr, hToken, desiredAccess,

(gdb)

0x77dd7c11 in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

0x7c90d38e in _libws2_32_a_iname ()

(gdb)

Single stepping until exit from function _libws2_32_a_iname,

which has no line number information.

NativeAccess (nativePath=0xae53e0 "t", mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:1723

1723            HeapFree(GetProcessHeap(), 0, sdPtr);

(gdb)

1724            CloseHandle(hToken);

(gdb)

1725            if (!accessYesNo) {

(gdb)

1726                Tcl_SetErrno(EACCES);

(gdb)

1727                return -1;

(gdb)

1743    }

(gdb) list

1738                Tcl_SetErrno(EACCES);

1739                return -1;

1740            }

1741        }

1742        return 0;

1743    }

1744    ^L

1745    /*

1746     *----------------------------------------------------------------------

1747     *

(gdb) next

TclpObjAccess (pathPtr=0xae2408, mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/win/tclWinFile.c:2386

2386    }

(gdb)

Tcl_FSAccess (pathPtr=0xae2408, mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclIOUtil.c:2133

2133    }

(gdb)

CheckAccess (interp=0x3d7f48, pathPtr=0xae2408, mode=2)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclCmdAH.c:1411

1411        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value));

(gdb)

1413        return TCL_OK;

(gdb)

1414    }

(gdb)

Tcl_FileObjCmd (dummy=0x0, interp=0x3d7f48, objc=3, objv=0xa9d2b8)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclCmdAH.c:1376

1376    }

(gdb)

TclEvalObjvInternal (interp=0x3d7f48, objc=3, objv=0xa9d2b8,

    command=0xffffffff "P~º", length=-1, flags=0)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclBasic.c:3696

3696        if (TclAsyncReady(iPtr)) {

(gdb)

3699        if (code == TCL_OK && TclLimitReady(iPtr->limit)) {

(gdb)

3707        if (traced) {

(gdb)

3738        TclCleanupCommandMacro(cmdPtr);

(gdb)

3747        if (*(iPtr->result) != 0) {

(gdb)

3759        if (savedVarFramePtr) {

(gdb)

3762        return code;

(gdb) print code

$6 = 0

(gdb) next

3849    }

(gdb)

TclExecuteByteCode (interp=0x3d7f48, codePtr=0xae5338)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclExecute.c:2342

2342                CACHE_STACK_INFO();

(gdb)

2343                iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;

(gdb)

2345                if (result == TCL_OK) {

(gdb)

2349                    if (*(pc+pcAdjustment) == INST_POP) {

(gdb)

2361                    objResultPtr = Tcl_GetObjResult(interp);

(gdb)

2376                    TclNewObj(objPtr);

(gdb)

2377                    Tcl_IncrRefCount(objPtr);

(gdb)

2378                    iPtr->objResultPtr = objPtr;

(gdb)

2379                    NEXT_INST_V(pcAdjustment, objc, -1);

(gdb)

1794            switch (cleanup) {

(gdb)

1799                cleanup -= 2;

(gdb)

1800                while (cleanup--) {

(gdb)

1801                    valuePtr = POP_OBJECT();

(gdb)

1802                    TclDecrRefCount(valuePtr);

(gdb)

1800                while (cleanup--) {

(gdb)

1806                valuePtr = POP_OBJECT();

(gdb)

1807                TclDecrRefCount(valuePtr);

(gdb)

1810                valuePtr = OBJ_AT_TOS;

(gdb)

1811                TclDecrRefCount(valuePtr);

(gdb)

1813            OBJ_AT_TOS = objResultPtr;

(gdb)

1814            goto cleanup0;

(gdb)

1866        if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) {

(gdb)

1907        if (*pc == INST_LOAD_SCALAR1) {

(gdb)

1909        } else if (*pc == INST_PUSH1) {

(gdb)

1913        switch (*pc) {

(gdb)

1956            if (tosPtr > initTosPtr) {

(gdb)

1964                Tcl_SetObjResult(interp, OBJ_AT_TOS);

(gdb)

1972                goto checkForCatch;

(gdb)

7278            if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {

(gdb)

7286            iPtr->flags &= ~ERR_ALREADY_LOGGED;

(gdb)

7293            while ((expandNestList != NULL) && ((catchTop == initCatchTop) ||

(gdb)

7308            if (TclLimitExceeded(iPtr->limit)) {

(gdb)

7317            if (catchTop == initCatchTop) {

(gdb)

7324                goto abnormalReturn;

(gdb)

7379            while (tosPtr > initTosPtr) {

(gdb)

7380                Tcl_Obj *objPtr = POP_OBJECT();

(gdb)

7382                Tcl_DecrRefCount(objPtr);

(gdb)

7379            while (tosPtr > initTosPtr) {

(gdb)

7389            while (expandNestList) {

(gdb)

7395            if (tosPtr < initTosPtr) {

(gdb)

7405        TclArgumentBCRelease((Tcl_Interp*) iPtr,codePtr);

(gdb)

7411        TclStackFree(interp, initCatchTop+1);

(gdb)

7412        return result;

(gdb)

7414    }

(gdb) print result

$7 = 0

(gdb) next

TclCompEvalObj (interp=0x3d7f48, objPtr=0xae2450, invoker=0x0, word=0)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclExecute.c:1475

1475            codePtr->refCount--;

(gdb)

1476            if (codePtr->refCount <= 0) {

(gdb)

1500        iPtr->numLevels--;

(gdb)

1501        return result;

(gdb)

1502    }

(gdb)

TclEvalObjEx (interp=0x3d7f48, objPtr=0xae2450, flags=131072, invoker=0x0,

    word=0) at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclBasic.c:5102

5102            if (iPtr->numLevels == 0) {

(gdb)

5103                if (result == TCL_RETURN) {

(gdb)

5106                if ((result != TCL_OK) && (result != TCL_ERROR)

(gdb)

5114            iPtr->evalFlags = 0;

(gdb)

5115            iPtr->varFramePtr = savedVarFramePtr;

(gdb)

5119        TclDecrRefCount(objPtr);

(gdb)

5120        return result;

(gdb)

5121    }

(gdb)

Tcl_EvalObjEx (interp=0x3d7f48, objPtr=0xae2450, flags=131072)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclBasic.c:4904

4904    }

(gdb)

Tcl_RecordAndEvalObj (interp=0x3d7f48, cmdPtr=0xae2450, flags=131072)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclHistory.c:163

163         return result;

(gdb)

164     }

(gdb)

Tcl_Main (argc=-1, argv=0x3d269c, appInitProc=0x401378 <Tcl_AppInit>)

    at d:/msys/1.0/home/zeng/src/tcl8.5.6/generic/tclMain.c:555

555                 inChannel = Tcl_GetStdChannel(TCL_STDIN);

(gdb)

556                 outChannel = Tcl_GetStdChannel(TCL_STDOUT);

(gdb)

557                 errChannel = Tcl_GetStdChannel(TCL_STDERR);

(gdb)

558                 Tcl_DecrRefCount(commandPtr);

(gdb)

559                 commandPtr = Tcl_NewObj();

(gdb)

560                 Tcl_IncrRefCount(commandPtr);

(gdb)

561                 if (code != TCL_OK) {

(gdb)

566                 } else if (tty) {

(gdb)

567                     resultPtr = Tcl_GetObjResult(interp);

(gdb)

568                     Tcl_IncrRefCount(resultPtr);

(gdb)

569                     Tcl_GetStringFromObj(resultPtr, &length);

(gdb)

570                     if ((length > 0) && outChannel) {

(gdb)

571                         Tcl_WriteObj(outChannel, resultPtr);

(gdb)

572                         Tcl_WriteChars(outChannel, "\n", 1);

 

#

# result printed to tchsh

# 0

#

(gdb)

574                     Tcl_DecrRefCount(resultPtr);

(gdb)

489         while ((inChannel != (Tcl_Channel) NULL) && !Tcl_InterpDeleted(interp)) {

(gdb)

490             if (mainLoopProc == NULL) {

(gdb)

491                 if (tty) {

(gdb)

492                     Prompt(interp, &prompt);

(gdb)

493                     if (Tcl_InterpDeleted(interp)) {

(gdb)

496                     if (Tcl_LimitExceeded(interp)) {

(gdb)

499                     inChannel = Tcl_GetStdChannel(TCL_STDIN);

(gdb)

500                     if (inChannel == (Tcl_Channel) NULL) {

(gdb)

504                 if (Tcl_IsShared(commandPtr)) {

(gdb)

509                 length = Tcl_GetsObj(inChannel, commandPtr);

(gdb)

 

#

# now tclsh is ready to accept new input

#