Changeset 136398


Ignore:
Timestamp:
May 15, 2015, 10:46:22 PM (5 years ago)
Author:
cal@…
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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/base/src/darwintracelib1.0/darwintrace.c

    r129895 r136398  
    499499 */
    500500static void frecv(void *restrict buf, size_t size) {
    501         FILE *stream = __darwintrace_sock();
    502         if (1 != fread(buf, size, 1, stream)) {
    503                 if (ferror(stream)) {
    504                         perror("darwintrace: fread");
    505                 } else {
    506                         fprintf(stderr, "darwintrace: fread: end-of-file\n");
    507                 }
    508                 abort();
     501        /* We cannot safely use fread(3) here, because we're not in control of the
     502         * application's signal handling settings (which means we must assume
     503         * SA_RESTART isn't set) and fread(3) may return short without giving us
     504         * a way to know how many bytes have actually been read, i.e. without a way
     505         * to do the call again. Because of this great API design and
     506         * implementation on OS X, we'll just use read(2) here. */
     507        int fd = fileno(__darwintrace_sock());
     508        size_t count = 0;
     509        while (count < size) {
     510                ssize_t res = read(fd, buf + count, size - count);
     511                if (res < 0) {
     512                        if (errno == EINTR) {
     513                                continue;
     514                        }
     515                        perror("darwintrace: read");
     516                        abort();
     517                }
     518
     519                if (res == 0) {
     520                        fprintf(stderr, "darwintrace: read: end-of-file\n");
     521                        abort();
     522                }
     523
     524                count += res;
    509525        }
    510526}
     
    518534 */
    519535static void fsend(const void *restrict buf, size_t size) {
    520         FILE *stream = __darwintrace_sock();
    521         if (1 != fwrite(buf, size, 1, stream)) {
    522                 if (ferror(stream)) {
    523                         perror("darwintrace: fwrite");
    524                 } else {
    525                         fprintf(stderr, "darwintrace: fwrite: end-of-file\n");
    526                 }
    527                 abort();
    528         }
    529         fflush(stream);
     536        /* We cannot safely use fwrite(3) here, because we're not in control of the
     537         * application's signal handling settings (which means we must assume
     538         * SA_RESTART isn't set) and fwrite(3) may return short without giving us
     539         * a way to know how many bytes have actually been written, i.e. without
     540         * a way to do the call again. Because of this great API design and
     541         * implementation on OS X, we'll just use write(2) here. */
     542        int fd = fileno(__darwintrace_sock());
     543        size_t count = 0;
     544        while (count < size) {
     545                ssize_t res = write(fd, buf + count, size - count);
     546                if (res < 0) {
     547                        if (errno == EINTR) {
     548                                continue;
     549                        }
     550                        perror("darwintrace: write");
     551                        abort();
     552                }
     553
     554                count += res;
     555        }
    530556}
    531557
Note: See TracChangeset for help on using the changeset viewer.