[136398] trunk/base/src/darwintracelib1.0/darwintrace.c

cal at macports.org cal at macports.org
Fri May 15 15:46:22 PDT 2015


Revision: 136398
          https://trac.macports.org/changeset/136398
Author:   cal at macports.org
Date:     2015-05-15 15:46:22 -0700 (Fri, 15 May 2015)
Log Message:
-----------
base: darwintrace: don't use fread(3) and fwrite(3)

fread(3) and fwrite(3) can both be interrupted by signals, return a short
read/write or error and set errno=EINTR. Since there is no way to find out
whether the interrupted call has already read or written partial data, these
calls can never be re-called correctly without possible corruption. This is
a fundamental problem in the API and the implementation on OS X.

To avoid this, use write(2) and read(2) instead.

Modified Paths:
--------------
    trunk/base/src/darwintracelib1.0/darwintrace.c

Modified: trunk/base/src/darwintracelib1.0/darwintrace.c
===================================================================
--- trunk/base/src/darwintracelib1.0/darwintrace.c	2015-05-15 21:10:01 UTC (rev 136397)
+++ trunk/base/src/darwintracelib1.0/darwintrace.c	2015-05-15 22:46:22 UTC (rev 136398)
@@ -498,14 +498,30 @@
  * \param[in]  size number of bytes to read from the socket
  */
 static void frecv(void *restrict buf, size_t size) {
-	FILE *stream = __darwintrace_sock();
-	if (1 != fread(buf, size, 1, stream)) {
-		if (ferror(stream)) {
-			perror("darwintrace: fread");
-		} else {
-			fprintf(stderr, "darwintrace: fread: end-of-file\n");
+	/* We cannot safely use fread(3) here, because we're not in control of the
+	 * application's signal handling settings (which means we must assume
+	 * SA_RESTART isn't set) and fread(3) may return short without giving us
+	 * a way to know how many bytes have actually been read, i.e. without a way
+	 * to do the call again. Because of this great API design and
+	 * implementation on OS X, we'll just use read(2) here. */
+	int fd = fileno(__darwintrace_sock());
+	size_t count = 0;
+	while (count < size) {
+		ssize_t res = read(fd, buf + count, size - count);
+		if (res < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			perror("darwintrace: read");
+			abort();
 		}
-		abort();
+
+		if (res == 0) {
+			fprintf(stderr, "darwintrace: read: end-of-file\n");
+			abort();
+		}
+
+		count += res;
 	}
 }
 
@@ -517,16 +533,26 @@
  * \param[in] size number of bytes in the buffer
  */
 static void fsend(const void *restrict buf, size_t size) {
-	FILE *stream = __darwintrace_sock();
-	if (1 != fwrite(buf, size, 1, stream)) {
-		if (ferror(stream)) {
-			perror("darwintrace: fwrite");
-		} else {
-			fprintf(stderr, "darwintrace: fwrite: end-of-file\n");
+	/* We cannot safely use fwrite(3) here, because we're not in control of the
+	 * application's signal handling settings (which means we must assume
+	 * SA_RESTART isn't set) and fwrite(3) may return short without giving us
+	 * a way to know how many bytes have actually been written, i.e. without
+	 * a way to do the call again. Because of this great API design and
+	 * implementation on OS X, we'll just use write(2) here. */
+	int fd = fileno(__darwintrace_sock());
+	size_t count = 0;
+	while (count < size) {
+		ssize_t res = write(fd, buf + count, size - count);
+		if (res < 0) {
+			if (errno == EINTR) {
+				continue;
+			}
+			perror("darwintrace: write");
+			abort();
 		}
-		abort();
+
+		count += res;
 	}
-	fflush(stream);
 }
 
 /**
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20150515/3f4a6fe4/attachment.html>


More information about the macports-changes mailing list