summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml79
-rw-r--r--generic/tclIO.c26
-rw-r--r--unix/tclUnixSock.c49
3 files changed, 137 insertions, 17 deletions
diff --git a/.travis.yml b/.travis.yml
index 236bb2e..98ef72d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,15 @@
sudo: false
language: c
-
+addons:
+ apt:
+ packages:
+ - binutils-mingw-w64-i686
+ - binutils-mingw-w64-x86-64
+ - gcc-mingw-w64
+ - gcc-mingw-w64-base
+ - gcc-mingw-w64-i686
+ - gcc-mingw-w64-x86-64
+ - gcc-multilib
matrix:
include:
# Testing on Linux with various compilers
@@ -38,6 +47,13 @@ matrix:
env:
- BUILD_DIR=unix
- CFGOPT="--enable-symbols"
+ - name: "Linux/GCC/Mem-Debug"
+ os: linux
+ dist: bionic
+ compiler: gcc
+ env:
+ - BUILD_DIR=unix
+ - CFGOPT="--enable-symbols=mem"
# C++ build.
- name: "Linux/G++/Shared"
os: linux
@@ -111,6 +127,13 @@ matrix:
env:
- BUILD_DIR=unix
- CFGOPT="--enable-symbols"
+ - name: "Linux/Clang/Mem-Debug"
+ os: linux
+ dist: bionic
+ compiler: clang
+ env:
+ - BUILD_DIR=unix
+ - CFGOPT="--enable-symbols=mem"
# Testing on Mac, various styles
- name: "macOS/Xcode 11.3/Shared/Unix-like"
os: osx
@@ -177,13 +200,6 @@ matrix:
os: linux
dist: bionic
compiler: x86_64-w64-mingw32-gcc
- addons:
- apt:
- packages:
- - gcc-mingw-w64-base
- - binutils-mingw-w64-x86-64
- - gcc-mingw-w64-x86-64
- - gcc-mingw-w64
env:
- BUILD_DIR=win
- CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit"
@@ -198,14 +214,6 @@ matrix:
os: linux
dist: bionic
compiler: i686-w64-mingw32-gcc
- addons:
- apt:
- packages:
- - gcc-mingw-w64-base
- - binutils-mingw-w64-i686
- - gcc-mingw-w64-i686
- - gcc-mingw-w64
- - gcc-multilib
env:
- BUILD_DIR=win
- CFGOPT=--host=i686-w64-mingw32
@@ -260,6 +268,15 @@ matrix:
script:
- cmd.exe //C vcvarsall.bat x64 '&&' nmake 'OPTS=symbols' '-f' makefile.vc all tcltest
- cmd.exe //C vcvarsall.bat x64 '&&' nmake 'OPTS=symbols' '-f' makefile.vc test
+ - name: "Windows/MSVC/Mem-Debug"
+ os: windows
+ compiler: cl
+ env: *vcenv
+ before_install: *vcpreinst
+ install: []
+ script:
+ - cmd.exe //C vcvarsall.bat x64 '&&' nmake 'STATS=memdbg' '-f' makefile.vc all tcltest
+ - cmd.exe //C vcvarsall.bat x64 '&&' nmake 'STATS=memdbg' '-f' makefile.vc test
# Test on Windows with MSVC native (32-bit)
- name: "Windows/MSVC-x86/Shared"
os: windows
@@ -306,6 +323,15 @@ matrix:
script:
- cmd.exe //C vcvarsall.bat x86 '&&' nmake 'OPTS=symbols' '-f' makefile.vc all tcltest
- cmd.exe //C vcvarsall.bat x86 '&&' nmake 'OPTS=symbols' '-f' makefile.vc test
+ - name: "Windows/MSVC-x86/Mem-Debug"
+ os: windows
+ compiler: cl
+ env: *vcenv
+ before_install: *vcpreinst
+ install: []
+ script:
+ - cmd.exe //C vcvarsall.bat x86 '&&' nmake 'STATS=memdbg' '-f' makefile.vc all tcltest
+ - cmd.exe //C vcvarsall.bat x86 '&&' nmake 'STATS=memdbg' '-f' makefile.vc test
# Test on Windows with GCC native
- name: "Windows/GCC/Shared"
os: windows
@@ -353,6 +379,13 @@ matrix:
- BUILD_DIR=win
- CFGOPT="--enable-64bit --enable-symbols"
before_install: *makepreinst
+ - name: "Windows/GCC/Mem-Debug"
+ os: windows
+ compiler: gcc
+ env:
+ - BUILD_DIR=win
+ - CFGOPT="--enable-64bit --enable-symbols=mem"
+ before_install: *makepreinst
# Test on Windows with GCC native (32-bit)
- name: "Windows/GCC-x86/Shared"
os: windows
@@ -397,7 +430,21 @@ matrix:
- BUILD_DIR=win
- CFGOPT="--enable-symbols"
before_install: *makepreinst
+ - name: "Windows/GCC-x86/Mem-Debug"
+ os: windows
+ compiler: gcc
+ env:
+ - BUILD_DIR=win
+ - CFGOPT="--enable-symbols=mem"
+ before_install: *makepreinst
before_install:
+ - |-
+ case $TRAVIS_OS_NAME in
+ osx)
+ brew update
+ brew install libtommath
+ ;;
+ esac
- cd ${BUILD_DIR}
install:
- ./configure ${CFGOPT} --prefix=$HOME || (cat config.log && exit 1)
diff --git a/generic/tclIO.c b/generic/tclIO.c
index d65f6e6..edce09b 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -3219,6 +3219,9 @@ CutChannel(
*/
ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE);
+
+ /* Channel is not managed by any thread */
+ statePtr->managingThread = NULL;
}
void
@@ -3263,6 +3266,9 @@ Tcl_CutChannel(
for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) {
ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE);
}
+
+ /* Channel is not managed by any thread */
+ statePtr->managingThread = NULL;
}
/*
@@ -8390,6 +8396,13 @@ Tcl_NotifyChannel(
Tcl_Preserve(statePtr);
/*
+ * Avoid processing if the channel owner has been changed.
+ */
+ if (statePtr->managingThread != Tcl_GetCurrentThread()) {
+ goto done;
+ }
+
+ /*
* If we are flushing in the background, be sure to call FlushChannel for
* writable events. Note that we have to discard the writable event so we
* don't call any write handlers before the flush is complete.
@@ -8423,6 +8436,13 @@ Tcl_NotifyChannel(
} else {
chPtr = chPtr->nextPtr;
}
+
+ /*
+ * Stop if the channel owner has been changed in-between.
+ */
+ if (chanPtr->state->managingThread != Tcl_GetCurrentThread()) {
+ goto done;
+ }
}
/*
@@ -8440,6 +8460,7 @@ Tcl_NotifyChannel(
UpdateInterest(chanPtr);
}
+done:
Tcl_Release(statePtr);
TclChannelRelease(channel);
@@ -8939,6 +8960,11 @@ TclChannelEventScriptInvoker(
int result; /* Result of call to eval script. */
/*
+ * Be sure event executed in managed channel (covering bugs similar [f583715154]).
+ */
+ assert(chanPtr->state->managingThread == Tcl_GetCurrentThread());
+
+ /*
* We must preserve the interpreter so we can report errors on it later.
* Note that we do not need to preserve the channel because that is done
* by Tcl_NotifyChannel before calling channel handlers.
diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c
index 80de491..b707be4 100644
--- a/unix/tclUnixSock.c
+++ b/unix/tclUnixSock.c
@@ -129,6 +129,7 @@ struct TcpState {
* Static routines for this file:
*/
+static void TcpAsyncCallback(void *clientData, int mask);
static int TcpConnect(Tcl_Interp *interp, TcpState *state);
static void TcpAccept(void *data, int mask);
static int TcpBlockModeProc(void *data, int mode);
@@ -145,6 +146,7 @@ static int TcpInputProc(void *instanceData, char *buf,
int toRead, int *errorCode);
static int TcpOutputProc(void *instanceData,
const char *buf, int toWrite, int *errorCode);
+static void TcpThreadActionProc(void *instanceData, int action);
static void TcpWatchProc(void *instanceData, int mask);
static int WaitForConnect(TcpState *statePtr, int *errorCodePtr);
static void WrapNotify(void *clientData, int mask);
@@ -174,7 +176,7 @@ static const Tcl_ChannelType tcpChannelType = {
NULL, /* flush proc. */
NULL, /* handler proc. */
NULL, /* wide seek proc. */
- NULL, /* thread action proc. */
+ TcpThreadActionProc, /* thread action proc. */
NULL /* truncate proc. */
};
@@ -983,6 +985,51 @@ TcpGetOptionProc(
/*
* ----------------------------------------------------------------------
*
+ * TcpThreadActionProc --
+ *
+ * Handles detach/attach for asynchronously connecting socket.
+ *
+ * Reassigning the file handler associated with thread-related channel
+ * notification, responsible for callbacks (signaling that asynchronous
+ * connection attempt has succeeded or failed).
+ *
+ * Results:
+ * None.
+ *
+ * ----------------------------------------------------------------------
+ */
+
+static void
+TcpThreadActionProc(
+ void *instanceData,
+ int action)
+{
+ TcpState *statePtr = (TcpState *)instanceData;
+
+ if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
+ /*
+ * Async-connecting socket must get reassigned handler if it have been
+ * transferred to another thread. Remove the handler if the socket is
+ * not managed by this thread anymore and create new handler (TSD related)
+ * so the callback will run in the correct thread, bug [f583715154].
+ */
+ switch (action) {
+ case TCL_CHANNEL_THREAD_REMOVE:
+ CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
+ Tcl_DeleteFileHandler(statePtr->fds.fd);
+ break;
+ case TCL_CHANNEL_THREAD_INSERT:
+ Tcl_CreateFileHandler(statePtr->fds.fd,
+ TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback, statePtr);
+ SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
+ break;
+ }
+ }
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
* TcpWatchProc --
*
* Initialize the notifier to watch the fd from this channel.