Netscape buggy, kernel OK - some test results

Milan Kerslager milan.kerslager na spsselib.hiedu.cz
Pondělí Leden 25 00:03:01 CET 1999


Snad mi autor promine, ale odezva v linux-kernel na tenhle fix byla 
prizniva (vcetne 2.0.x). Jsou to dva maily, druhy se venuje uprave pro 
libc5.
                M.

------- Forwarded Message Follows -------

From:           Stanislav Meduna <stano na trillian.eunet.sk>
Subject:        Re: Netscape buggy, kernel OK - some test results
To:             linux-kernel na vger.rutgers.edu
Date sent:      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 na 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);
}
========


------- Forwarded Message Follows -------

Date sent:      Sat, 23 Jan 1999 19:47:02 -0500 (EST)
From:           Rafael Reilova <rreilova na ececs.uc.edu>
To:             Stanislav Meduna <stano na trillian.eunet.sk>
Copies to:      linux-kernel na vger.rutgers.edu
Subject:        Re: Netscape buggy, kernel OK - some test results

On Sat, 23 Jan 1999, Stanislav Meduna wrote:

> > 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.

This hack works perfectly, thanks a lot!  So far zero hangs.  Pages seem
to also download with less stalling (esp. connections to MS-IIS). In 
case anyone is using the libc5 version of netscape make sure to change 
the line below: 

 {
   int i;
 
-   dlhdl = dlopen("/lib/libc.so.6", RTLD_NOW);
+   dlhdl = dlopen("/lib/libc.so.5", RTLD_NOW);
 
   if (! dlhdl)
     exit(99);
 

and also to link against libdl.so.1, use

ld -shared -o libnspipepatch.so /lib/libdl.so.1 nspipepatch.o

Otherwise, you'll get an instant segfault  :-0

        Cheers,

            Rafael


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" 
in
the body of a message to majordomo na vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/


Další informace o konferenci Linux