Protect against concurrent access when doing fclose and fdopen
authorStefan Vogel <sv@exept.de>
Tue, 29 Nov 2011 13:07:21 +0100
changeset 2680 ff00563f0444
parent 2679 cfab54d30fcc
child 2681 c927d2c3f48b
Protect against concurrent access when doing fclose and fdopen
Socket.st
--- a/Socket.st	Tue Nov 29 11:56:14 2011 +0100
+++ b/Socket.st	Tue Nov 29 13:07:21 2011 +0100
@@ -2632,7 +2632,7 @@
     self primitiveFailed
 ! !
 
-!Socket methodsFor:'low level'!
+!Socket protectedMethodsFor:'low level'!
 
 closeFile
     "low level close"
@@ -2643,57 +2643,61 @@
 
     t = __INST(handle);
     if (t != nil) {
-	FILE *fp;
-	SOCKET sock;
-	int fd;
-
-	__INST(handle) = nil;
-	fp = __FILEVal(t);
-	fd = fileno(fp);
-	sock = SOCKET_FROM_FD(fd);
+        FILE *fp;
+        SOCKET sock;
+        int fd;
+
+        __INST(handle) = nil;
+        fp = __FILEVal(t);
+        fd = fileno(fp);
+        sock = SOCKET_FROM_FD(fd);
 
 # ifdef DO_WRAP_CALLS
-	{ int ret;
-	/*__setWrapCallDebugging(1,1); */
-
-	  do {
-	    __threadErrno = 0;
-	    ret = STX_C_NOINT_CALL1("fclose", fclose, fp);
-	  } while ((ret < 0) && (__threadErrno == EINTR));
-
-#  ifdef WIN32
-	  do {
-	    __threadErrno = 0;
-	    ret = STX_WSA_NOINT_CALL1("closesocket", closesocket, sock);
-	  } while ((ret < 0) && (__threadErrno == EINTR));
-	  closesocket(sock);
+        { 
+          int ret;
+          /*__setWrapCallDebugging(1,1); */
+
+          __stxWrapApiEnterCritical();
+          do {
+            __threadErrno = 0;
+            ret = STX_C_NOINT_CALL1("fclose", fclose, fp);
+          } while ((ret < 0) && (__threadErrno == EINTR));
+
+#  if defined(WIN32) && defined(CLOSESOCKET_AFTER_FCLOSE)
+          do {
+            __threadErrno = 0;
+            ret = STX_WSA_NOINT_CALL1("closesocket", closesocket, sock);
+          } while ((ret < 0) && (__threadErrno == EINTR));
 #  endif
-	/*__setWrapCallDebugging(1,0);*/
-	}
+          __stxWrapLeaveCritical();
+          /*__setWrapCallDebugging(1,0);*/
+        }
 # else /* !DO_WRAP_CALLS */
 
-	DBGFPRINTF((stderr, "SOCKET: fflush %x (%d %d)\n", fp, fileno(fp), sock));
-	fflush(fp);
+        DBGFPRINTF((stderr, "SOCKET: fflush %x (%d %d)\n", fp, fileno(fp), sock));
+        fflush(fp);
 
 #  if defined(CLOSESOCKET_BEFORE_FCLOSE)
-	DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
-	closesocket(sock);
+        DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
+        closesocket(sock);
 #  endif
-	if ((@global(FileOpenTrace) == true) || __debugging__) {
-	    console_fprintf(stderr, "SOCKET: fclose %x (%d %d)\n", fp, fileno(fp), sock);
-	}
-	fclose(fp);
+        if ((@global(FileOpenTrace) == true) || __debugging__) {
+            console_fprintf(stderr, "SOCKET: fclose %x (%d %d)\n", fp, fileno(fp), sock);
+        }
+        fclose(fp);
 
 #  if defined(CLOSESOCKET_AFTER_FCLOSE)
-	DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
-	closesocket(sock);
+        DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock));
+        closesocket(sock);
 #  endif
 
 # endif /* !DO_WRAP_CALLS */
     }
 #endif /* NO_SOCKET */
 %}
-!
+! !
+
+!Socket methodsFor:'low level'!
 
 getSocketAdress
     "BAD SPELLING, of #getSocketAddress, kept for compatibility with swazoo"
@@ -2797,22 +2801,22 @@
     |serverSocketFd addr addrLen domainClass|
 
     handle notNil ifTrue:[
-	^ self errorAlreadyOpen
+        ^ self errorAlreadyOpen
     ].
 
     domain := aSocket domain.
     socketType := aSocket type.
     serverSocketFd := aSocket fileDescriptor.
     serverSocketFd isNil ifTrue:[
-	^ self error:'invalid server socket'
+        ^ self error:'invalid server socket'
     ].
     (serverSocketFd isMemberOf:SmallInteger) ifFalse:[
-	^ self error:'invalid server socket'
+        ^ self error:'invalid server socket'
     ].
 
     domainClass := self class socketAddressClassForDomain:domain.
     domainClass isNil ifTrue:[
-	^ self error:'invalid (unsupported) domain'.
+        ^ self error:'invalid (unsupported) domain'.
     ].
     addrLen := domainClass socketAddressSize.
     addr := domainClass new.
@@ -2826,32 +2830,36 @@
     unsigned int alen, alen0;
     struct hostent *he ;
     char dotted[20] ;
+#ifdef DO_WRAP_CALLS
+    extern void __stxWrapApiEnterCritical(), __stxWrapApiLeaveCritical();
+#endif
+
 
     if (!__isSmallInteger(addrLen)) {
-	DBGPRINTF(("SOCKET: bad addrLen\n"));
-	RETURN (false);
+        DBGPRINTF(("SOCKET: bad addrLen\n"));
+        RETURN (false);
     }
     alen0 = __intVal(addrLen);
     sock = SOCKET_FROM_FD(__intVal(serverSocketFd));
 
     if (blocking == false) {
 # if defined(O_NONBLOCK) && defined(SET_NDELAY)
-	flags = fcntl(sock, F_GETFL);
-	fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+        flags = fcntl(sock, F_GETFL);
+        fcntl(sock, F_SETFL, flags | O_NONBLOCK);
 # endif
     }
 
 # ifdef DO_WRAP_CALLS
     do {
-	__threadErrno = 0;
-	alen = alen0;
-	newSock = STX_WSA_CALL3("accept", accept, sock, &sa, &alen);
+        __threadErrno = 0;
+        alen = alen0;
+        newSock = STX_WSA_CALL3("accept", accept, sock, &sa, &alen);
     } while ((newSock < 0) && (__threadErrno == EINTR));
 # else
     __BEGIN_INTERRUPTABLE__
     do {
-	alen = alen0;
-	newSock = accept(sock, (struct sockaddr *) &sa, &alen);
+        alen = alen0;
+        newSock = accept(sock, (struct sockaddr *) &sa, &alen);
     } while ((newSock < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
 # endif
@@ -2859,43 +2867,43 @@
 
     if (blocking == false) {
 # if defined(O_NDELAY) && defined(SET_NDELAY)
-	fcntl(sock, F_SETFL, flags);
+        fcntl(sock, F_SETFL, flags);
 # endif
     }
 
     if (newSock < 0) {
-	DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
-	RETURN (false);
+        DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno));
+        __INST(lastErrorNumber) = __MKSMALLINT(errno);
+        RETURN (false);
     }
 
     if (__isNonNilObject(addr)) {
-	OBJ oClass;
-	int nInstVars, nInstBytes, objSize;
-	char *cp;
-
-	oClass = __qClass(addr);
-	if (! __isBytes(addr) ) {
-	    DBGPRINTF(("SOCKET: bad addr\n"));
-	    closesocket(newSock);
-	    RETURN (false);
-	}
-
-	nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
-	nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ));
-	objSize = __qSize(addr) - nInstBytes;
-	cp = (char *)__InstPtr(addr) + nInstBytes;
-	if (objSize < alen) {
-	    DBGPRINTF(("SOCKET: bad addr\n"));
-	    closesocket(newSock);
-	    RETURN (false);
-	}
-
-	/*
-	 * extract the partners address
-	 */
-	bcopy((char *)&sa, cp, alen);
-	addrLen = __MKSMALLINT(alen);
+        OBJ oClass;
+        int nInstVars, nInstBytes, objSize;
+        char *cp;
+
+        oClass = __qClass(addr);
+        if (! __isBytes(addr) ) {
+            DBGPRINTF(("SOCKET: bad addr\n"));
+            closesocket(newSock);
+            RETURN (false);
+        }
+
+        nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars);
+        nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ));
+        objSize = __qSize(addr) - nInstBytes;
+        cp = (char *)__InstPtr(addr) + nInstBytes;
+        if (objSize < alen) {
+            DBGPRINTF(("SOCKET: bad addr\n"));
+            closesocket(newSock);
+            RETURN (false);
+        }
+
+        /*
+         * extract the partners address
+         */
+        bcopy((char *)&sa, cp, alen);
+        addrLen = __MKSMALLINT(alen);
     }
 
     /*
@@ -2903,43 +2911,45 @@
      */
 # ifdef WIN32
     {
-	int _fd = _open_osfhandle((long)newSock, 0);
-	fp = fdopen(_fd, "r+");
-	DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",newSock,_fd, fp));
+        __stxWrapApiEnterCritical();
+        int _fd = _open_osfhandle((long)newSock, 0);
+        fp = fdopen(_fd, "r+");
+        __stxWrapApiLeaveCritical();
+        DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",newSock,_fd, fp));
     }
 # else
     fp = fdopen(newSock, "r+");
 # endif
 
     if (! fp) {
-	DBGPRINTF(("SOCKET: fdopen call failed\n"));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
+        DBGPRINTF(("SOCKET: fdopen call failed\n"));
+        __INST(lastErrorNumber) = __MKSMALLINT(errno);
 #  ifdef DO_WRAP_CALLS
-	{
-	  int ret;
-	  do {
-	      __threadErrno = 0;
-	      ret = STX_WSA_CALL1("closesocket", closesocket, newSock);
-	  } while ((ret < 0) && (__threadErrno == EINTR));
-	}
+        {
+          int ret;
+          do {
+              __threadErrno = 0;
+              ret = STX_WSA_CALL1("closesocket", closesocket, newSock);
+          } while ((ret < 0) && (__threadErrno == EINTR));
+        }
 #  else
-	closesocket(newSock);
+        closesocket(newSock);
 #  endif
-	DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
-	RETURN (false);
+        DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock));
+        RETURN (false);
     }
     __INST(handleType) = @symbol(socketFilePointer);
 
     if ((@global(FileOpenTrace) == true) || __debugging__) {
 # ifdef WIN32
-	{
-	    HANDLE h;
-	    int _fd = fileno(fp);
-	    h = (HANDLE)_get_osfhandle(_fd);
-	    console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d) (H: %x)\n", fp, _fd, h);
-	}
+        {
+            HANDLE h;
+            int _fd = fileno(fp);
+            h = (HANDLE)_get_osfhandle(_fd);
+            console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d) (H: %x)\n", fp, _fd, h);
+        }
 # else
-	console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d)\n", fp, newSock);
+        console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d)\n", fp, newSock);
 # endif
     }
 
@@ -2957,11 +2967,11 @@
     // object.
 # endif
     {
-	OBJ t;
-
-	t = __MKEXTERNALADDRESS(fp);
-	__INST(handle) = t;
-	__STORE(self, t);
+        OBJ t;
+
+        t = __MKEXTERNALADDRESS(fp);
+        __INST(handle) = t;
+        __STORE(self, t);
     }
 #endif /* not NO_SOCKET */
 %}.
@@ -2971,7 +2981,7 @@
     port := aSocket port.
 
     addr notNil ifTrue:[
-	peer := addr.
+        peer := addr.
     ].
 
     ^ true
@@ -3454,7 +3464,7 @@
     |domainName domainCode typeCode error|
 
     handle notNil ifTrue:[
-	^ self errorAlreadyOpen
+        ^ self errorAlreadyOpen
     ].
     domainName := SocketAddress domainCodeFromName:domainArg.
     domainCode := OperatingSystem domainCodeOf:domainName.
@@ -3468,19 +3478,19 @@
     SOCKET sock;
 
     if (! __isSmallInteger(domainCode)) {
-	error = @symbol(badArgument1);
-	goto out;
+        error = @symbol(badArgument1);
+        goto out;
     }
     if (! __isSmallInteger(typeCode)) {
-	error = @symbol(badArgument2);
-	goto out;
+        error = @symbol(badArgument2);
+        goto out;
     }
     if (protocolNumber != nil) {
-	if (!__isSmallInteger(protocolNumber)) {
-	    error = @symbol(badArgument3);
-	    goto out;
-	}
-	proto = __intVal(protocolNumber);
+        if (!__isSmallInteger(protocolNumber)) {
+            error = @symbol(badArgument3);
+            goto out;
+        }
+        proto = __intVal(protocolNumber);
     }
 
 
@@ -3493,20 +3503,20 @@
 # ifdef SOCKET_BLOCKS
 #  ifdef DO_WRAP_CALLS
     do {
-	__threadErrno = 0;
-	sock = STX_WSA_NOINT_CALL3("socket", socket, dom, typ, proto);
+        __threadErrno = 0;
+        sock = STX_WSA_NOINT_CALL3("socket", socket, dom, typ, proto);
     } while ((sock < 0) && (__threadErrno == EINTR));
 #  else
     __BEGIN_INTERRUPTABLE__
     do {
-	DBGPRINTF(("SOCKET: opening socket domain=%d type=%d proto=%d\n", dom, typ, proto));
-	sock = socket(dom, typ, proto);
+        DBGPRINTF(("SOCKET: opening socket domain=%d type=%d proto=%d\n", dom, typ, proto));
+        sock = socket(dom, typ, proto);
 #   if defined(EPROTONOSUPPORT) /* for SGI */
-	if ((proto != 0) && (sock < 0) && (errno == EPROTONOSUPPORT)) {
-	    DBGPRINTF(("SOCKET: retry with UNSPEC protocol\n"));
-	    proto = 0;
-	    sock = socket(dom, typ, 0);
-	}
+        if ((proto != 0) && (sock < 0) && (errno == EPROTONOSUPPORT)) {
+            DBGPRINTF(("SOCKET: retry with UNSPEC protocol\n"));
+            proto = 0;
+            sock = socket(dom, typ, 0);
+        }
 #   endif
     } while ((sock < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
@@ -3515,9 +3525,9 @@
     sock = socket(dom, typ, proto);
 #  if defined(EPROTONOSUPPORT) /* for SGI */
     if ((proto != 0) && (sock < 0) && (errno == EPROTONOSUPPORT)) {
-	DBGPRINTF(("SOCKET: retry with UNSPEC protocol\n"));
-	proto = 0;
-	sock = socket(dom, typ, 0);
+        DBGPRINTF(("SOCKET: retry with UNSPEC protocol\n"));
+        proto = 0;
+        sock = socket(dom, typ, 0);
     }
 #  endif
 # endif
@@ -3530,91 +3540,95 @@
     if (sock < 0)
 # endif
     {
-	DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=%d) call failed errno=%d\n", dom, typ, proto, errno));
-	__INST(lastErrorNumber) = __MKSMALLINT(errno);
+        DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=%d) call failed errno=%d\n", dom, typ, proto, errno));
+        __INST(lastErrorNumber) = __MKSMALLINT(errno);
     } else {
 # ifdef SO_REUSEADDR
-	if (reuse == true) {
-	    DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR\n"));
-	    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
-		DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
-	    }
-	}
+        if (reuse == true) {
+            DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR\n"));
+            if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
+                DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
+            }
+        }
 # endif /* SO_REUSEADDR */
 
 # ifdef SET_LINGER_WHEN_CREATING_SOCKET
 #  ifdef SO_LINGER
-	{
-	    struct linger l;
-
-	    l.l_onoff = 1;
-	    l.l_linger = 30;
-	    setsockopt( sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
-	}
+        {
+            struct linger l;
+
+            l.l_onoff = 1;
+            l.l_linger = 30;
+            setsockopt( sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+        }
 #  endif
 # endif
 # ifdef WIN32
-	/*
-	 * make it blocking
-	 */
-	{
-	    int zero = 0;
-
-	    ioctlsocket(sock, FIONBIO, &zero);
-	}
-# endif
-	/*
-	 * make it a FILE *
-	 */
-# ifdef WIN32
-	{
-	    int _fd = _open_osfhandle((long)sock, 0);
-	    fp = fdopen(_fd, "r+");
-	    DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",sock,_fd, fp));
-	}
-# else
-	fp = fdopen(sock, "r+");
+        /*
+         * make it blocking
+         */
+        {
+            int zero = 0;
+
+            ioctlsocket(sock, FIONBIO, &zero);
+        }
 # endif
-	if (! fp) {
-	    DBGPRINTF(("SOCKET: fdopen call failed\n"));
-	    __INST(lastErrorNumber) = __MKSMALLINT(errno);
-# ifdef DO_WRAP_CALLS
-	    { int ret;
-
-	      do {
-		__threadErrno = 0;
-		ret = STX_WSA_NOINT_CALL1("closesocket", closesocket, sock);
-	      } while ((ret < 0) && (__threadErrno == EINTR));
-	    }
+        /*
+         * make it a FILE *
+         */
+# ifdef WIN32
+        {
+            extern void __stxWrapApiEnterCritical(), __stxWrapApiLeaveCritical();
+
+            __stxWrapApiEnterCritical();
+            int _fd = _open_osfhandle((long)sock, 0);
+            fp = fdopen(_fd, "r+");
+            __stxWrapApiLeaveCritical();
+            DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",sock,_fd, fp));
+        }
 # else
-	    __BEGIN_INTERRUPTABLE__
-	    closesocket(sock);
-	    DBGFPRINTF((stderr, "SOCKET: fdopen failed (%d)\n", sock));
-	    __END_INTERRUPTABLE__
+        fp = fdopen(sock, "r+");
 # endif
-	} else {
-	    __INST(handleType) = @symbol(socketFilePointer);
-
-	    if ((@global(FileOpenTrace) == true) || __debugging__) {
-		console_fprintf(stderr, "fdopen [Socket] -> %x\n", fp);
-	    }
+        if (! fp) {
+            DBGPRINTF(("SOCKET: fdopen call failed\n"));
+            __INST(lastErrorNumber) = __MKSMALLINT(errno);
+# ifdef DO_WRAP_CALLS
+            { int ret;
+
+              do {
+                __threadErrno = 0;
+                ret = STX_WSA_NOINT_CALL1("closesocket", closesocket, sock);
+              } while ((ret < 0) && (__threadErrno == EINTR));
+            }
+# else
+            __BEGIN_INTERRUPTABLE__
+            closesocket(sock);
+            DBGFPRINTF((stderr, "SOCKET: fdopen failed (%d)\n", sock));
+            __END_INTERRUPTABLE__
+# endif
+        } else {
+            __INST(handleType) = @symbol(socketFilePointer);
+
+            if ((@global(FileOpenTrace) == true) || __debugging__) {
+                console_fprintf(stderr, "fdopen [Socket] -> %x\n", fp);
+            }
 
 # if 0
-	    // The original code was:
-	    __INST(handle) = __MKEXTERNALADDRESS(fp); __STORESELF(handle);
-	    // but for that, gcc generates wrong code, which loads self (volatile) into
-	    // a register (bp), then calls __MKEXTERNALADDRESS, then stores indirect bp.
-	    // That is wrong if a scavenge occurs in __MKEXTERNALADDRESS, as bp is now still pointing to the old
-	    // object.
+            // The original code was:
+            __INST(handle) = __MKEXTERNALADDRESS(fp); __STORESELF(handle);
+            // but for that, gcc generates wrong code, which loads self (volatile) into
+            // a register (bp), then calls __MKEXTERNALADDRESS, then stores indirect bp.
+            // That is wrong if a scavenge occurs in __MKEXTERNALADDRESS, as bp is now still pointing to the old
+            // object.
 # endif
-	    {
-		OBJ t;
-
-		t = __MKEXTERNALADDRESS(fp);
-		__INST(handle) = t;
-		__STORE(self, t);
-	    }
-	}
+            {
+                OBJ t;
+
+                t = __MKEXTERNALADDRESS(fp);
+                __INST(handle) = t;
+                __STORE(self, t);
+            }
+        }
     }
 #endif
 out:;
@@ -3622,14 +3636,14 @@
 
     "all ok?"
     handle notNil ifTrue:[
-	domain := domainArg.
-	socketType := typeArg.
-	Lobby register:self.
+        domain := domainArg.
+        socketType := typeArg.
+        Lobby register:self.
     ] ifFalse:[
-	error notNil ifTrue:[
-	    ^ self primitiveFailed:error.
-	].
-	^ self openError
+        error notNil ifTrue:[
+            ^ self primitiveFailed:error.
+        ].
+        ^ self openError
     ].
 
     "
@@ -3993,9 +4007,9 @@
 !Socket class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.261 2011-07-20 18:49:19 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.262 2011-11-29 12:07:21 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.261 2011-07-20 18:49:19 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.262 2011-11-29 12:07:21 stefan Exp $'
 ! !