From: Stanislav Meduna <stano@trillian.eunet.sk> Subject: Re: Netscape buggy, kernel OK - some test results To: linux-kernel@vger.rutgers.edu Date: Sat, 23 Jan 1999 19:00:24 +0100 (CET) > I'll try to polish my hack a bit - seems like > it can help more people. Those who have problem with freezing netscape, please try the following code. If it helps, we are sure that the kernel is not the problem. It works for me with 2.2.0-final and Netscape 4.5, I have not tested it very carefully and I don't guarantee it works anywhere else. Thanks Stano ======== #include <dlfcn.h> #include <unistd.h> #include <limits.h> /* This is a netscape bug workaround. Search for a pipe, where only 1 byte strings \0372 are written to the write end and only 1 byte strings are requested back. Count the difference and fake any writes that would cause an overflow of the pipe and corresponding reads. This is a really dirty hack with almost no error checking and relying on the netscape's behaviour. Compile with gcc -c nspipepatch.c ld -shared -o libnspipepatch.so -ldl nspipepatch.o and add LD_PRELOAD=<path>/libnspipepatch.so to your netscape starting script. (C) 1999 Stanislav Meduna <stano@trillian.eunet.sk> There is absolutely NO WARRANTY. The use and distribution is completely free */ /* The magic netscape char flowing through the pipe */ #define MAGIC ((unsigned char) '\372') /* libc handle for dlsym */ static void *dlhdl=0; /* pointers to overloaded functions */ static int (*pipe_fp)(int [2])=0; static ssize_t (*write_fp)(int, const void *, size_t)=0; static ssize_t (*read_fp)(int, void *, size_t)=0; static int (*close_fp)(int)=0; /* we keep the info about our descriptors here */ static struct nshack_pipe_t { /* If this is a pipe that could be our one, mark both ends here. If we shouldn't touch the descriptor, enter -1 here */ int read_end, write_end; /* The difference between writes and reads, maintained on the write end */ int diff; /* Number of faked writes, maintained on the write end */ int faked; } fdflags[256]; /* Mark the descriptors as unused or not of our interest */ static void clearfd(int fd) { fdflags[fd].read_end = fdflags[fd].write_end = -1; fdflags[fd].diff = fdflags[fd].faked = 0; } /* Clear both ends */ static void clearboth(int fd) { int rd = fdflags[fd].read_end; int wr = fdflags[fd].write_end; if (rd >= 0) clearfd(rd); if (wr >= 0) clearfd(wr); } /* Init the pointers to overloaded functions */ static void initptrs() { int i; dlhdl = dlopen("/lib/libc.so.6", RTLD_NOW); if (! dlhdl) exit(99); pipe_fp = dlsym(dlhdl, "pipe"); write_fp = dlsym(dlhdl, "write"); read_fp = dlsym(dlhdl, "read"); close_fp = dlsym(dlhdl, "close"); if (! pipe_fp || ! write_fp || ! read_fp || ! close_fp) exit(99); for (i=0; i < sizeof(fdflags)/sizeof(fdflags[0]); i++) clearfd(i); } /* Unload the library */ void _fini() { if (dlhdl) dlclose(dlhdl); } /* Overloaded pipe - mark the fresh pipes */ int pipe(int fd[2]) { int res; if (! pipe_fp) initptrs(); res = (*pipe_fp)(fd); if (! res) { /* This could be our pipe - watch it during read/write */ fdflags[fd[0]].read_end = fdflags[fd[1]].read_end = fd[0]; fdflags[fd[0]].write_end = fdflags[fd[1]].write_end= fd[1]; fdflags[fd[0]].diff = fdflags[fd[1]].faked = 0; } return res; } /* Overloaded write */ ssize_t write(int fd, const void *buf, size_t cnt) { int res=0; if (! write_fp) initptrs(); if (cnt != 1 || *(unsigned char *)buf != MAGIC) clearboth(fd); /* This is not our pipe - magic not seen */ if (fd == fdflags[fd].write_end) { /* This is the write end of a watched pipe */ fdflags[fd].diff++; /* Play safe - reduce the allowed difference to guard against off-by-one errors and similar :-) */ if (fdflags[fd].diff >= PIPE_BUF-64) { /* We fake the write */ fdflags[fd].faked++; res = 1; } else res = (*write_fp)(fd, buf, cnt); } else res = (*write_fp)(fd, buf, cnt); return res; } /* Overloaded read */ ssize_t read(int fd, void *buf, size_t cnt) { int res; int watch=0; if (! read_fp) initptrs(); if (fd == fdflags[fd].read_end) { if (cnt == 1) watch = 1; else clearboth(fd); /* The true one always wants one char only */ /* This is the read end of a watched pipe */ if (watch && fdflags[fdflags[fd].write_end].faked) { /* Faked writes exist - compensate with faked reads */ fdflags[fdflags[fd].write_end].faked--; fdflags[fdflags[fd].write_end].diff--; *((unsigned char *) buf) = MAGIC; return 1; } } /* Do the real read */ res = (*read_fp)(fd, buf, cnt); if (watch && res == 1) { /* If we watch the pipe and the read was successfull, use the read value to make sure this is THE pipe. */ if (*((unsigned char *) buf) == MAGIC) fdflags[fd].diff--; else clearboth(fd); } return res; } /* Overloaded close (we want to be at least a bit correct) */ int close(int fd) { if (! close_fp) initptrs(); if (fd == fdflags[fd].read_end || fd == fdflags[fd].write_end) clearboth(fd); return (*close_fp)(fd); } ======== - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/