Bug 7684 - nis/ypclnt.c leaks file descriptors if ypbind is called
Summary: nis/ypclnt.c leaks file descriptors if ypbind is called
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: glibc
Version: 6.1
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Cristian Gafton
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 1999-12-08 16:44 UTC by Scott Sutherland
Modified: 2008-05-01 15:37 UTC (History)
0 users

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2000-03-08 20:17:04 UTC
Embargoed:


Attachments (Terms of Use)

Description Scott Sutherland 1999-12-08 16:44:37 UTC
The file ypclnt.c in the glibc-2.1 distribution has a file descriptor leak.
In particular, if ypbind is called prior to any other NIS calls (except
ypunbind), each subsequent call will leave a UDP connection open.  This is
because ypbind caches the connection, but the subsequent calls overwrite it
with a new one each time.  If you don't call ypbind first, there is no
problem.  A patch which fixes the trouble is at the end of this message.

The problem also exists in RedHat 6.0, and probably other versions.

(note that this bug was also submitted by email.  Sorry if I created a
duplicate)

The following C program demonstrates the problem.

/*****************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/yp.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/ypupd.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <bits/libc-lock.h>

main () {
  char  domain[YPMAXDOMAIN];
  unsigned int order;
  int yp_order_result;
  int i;
#define NUMCHECKS 10
  char *master;
  char *mapname = "services.byname";
  unsigned char openfile[5*NUMCHECKS];
  int fd;
  struct stat fdstat;
  char **mapkey;
  int  mapkeylen[NUMCHECKS];
  char  *mapval;
  int   mapvallen;

  mapkey = (char **)malloc(NUMCHECKS*(sizeof(char *)));

  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (fstat(fd, &fdstat) == 0) {
      openfile[fd] = 1;
    } else {
      openfile[fd] = 0;
    }
  }

  if (getdomainname(domain, sizeof(domain)) < 0) {
    fprintf(stderr,"NIS not running\n");
    exit(1);
  }


  if (  yp_bind(domain) ) {
    fprintf(stderr,"cant bind to domain %s\n");
    exit(1);
  }
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by ypbind (this is to be expected)\n",fd);
      openfile[fd] = 1;
    }
  }


  yp_order(domain, mapname, &order);
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by yp_order\n", fd);
      openfile[fd] = 1;
    }
  }


  yp_first(domain, mapname, mapkey, mapkeylen, &mapval, &mapvallen);
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by yp_first\n",fd);
      openfile[fd] = 1;
    }
  }

  for (i=1; i<NUMCHECKS; i++) {
    if (YPERR_NOMORE == yp_next(domain, mapname,
                                mapkey[i-1], mapkeylen[i-1],
                                &(mapkey[i]), &(mapkeylen[i]),
                                &mapval, &mapvallen))
      break;
  }
  for (fd=0; fd<5*NUMCHECKS; fd++) {
    if (!openfile[fd] && fstat(fd, &fdstat) == 0) {
      printf("fd %d left open by yp_next\n",fd);
      openfile[fd] = 1;
    }
  }

}
 /*****************************************************************/

Solution: A patch which remedies the problem is below.  It also fixes a
typo
 in a comment (exits was written as exists, which was worse than no
comment!)

nesconset <nis> diff -c2 ypclnt.c.orig ypclnt.c
*** glibc-2.1/nis/ypclnt.c.orig       Wed Jun 30 11:59:21 1999
--- glibc-2.1/nis/ypclnt.c    Wed Dec  8 10:12:32 1999
***************
*** 202,208 ****
          }

!       ysd->dom_socket = RPC_ANYSOCK;
!       ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG,
YPVERS,
!                                         UDPTIMEOUT, &ysd->dom_socket);
        if (ysd->dom_client == NULL)
          ysd->dom_vers = -1;
--- 202,212 ----
          }

!       /* if we don't already have a socket from a previous call, get one
*/
!       if ( ysd->dom_socket < 1 ) {
!       ysd->dom_socket = RPC_ANYSOCK;
!       ysd->dom_client = clntudp_create (&ysd->dom_server_addr,
!                                         YPPROG, YPVERS, UDPTIMEOUT,
!                                         &ysd->dom_socket);
!       }
        if (ysd->dom_client == NULL)
          ysd->dom_vers = -1;
***************
*** 211,215 ****
    while (ysd->dom_client == NULL);

!   /* If the program exists, close the socket */
    if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
      perror ("fcntl: F_SETFD");
--- 215,219 ----
    while (ysd->dom_client == NULL);

!   /* If the program exits, close the socket */
    if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
      perror ("fcntl: F_SETFD");

Comment 1 Jeff Johnson 2000-03-08 20:17:59 UTC
This problem appears to be resolved (ypc.c is the test program above, run
on ultrasparc):
bash$ cc     ypc.c   -o ypc -lnsl
bash$ ./ypc
fd 4 left open by ypbind (this is to be expected)
bash$ rpm -qf /usr/lib/libnsl.a
glibc-devel-2.1.3-15


Note You need to log in before you can comment on or make changes to this bug.