Index: head/sys/kern/kern_descrip.c =================================================================== --- head/sys/kern/kern_descrip.c +++ head/sys/kern/kern_descrip.c @@ -870,7 +870,7 @@ struct filedesc *fdp; struct filedescent *oldfde, *newfde; struct proc *p; - struct file *delfp; + struct file *delfp, *oldfp; u_long *oioctls, *nioctls; int error, maxfd; @@ -910,7 +910,8 @@ } oldfde = &fdp->fd_ofiles[old]; - if (!fhold(oldfde->fde_file)) + oldfp = oldfde->fde_file; + if (!fhold(oldfp)) goto unlock; /* @@ -922,14 +923,14 @@ case FDDUP_NORMAL: case FDDUP_FCNTL: if ((error = fdalloc(td, new, &new)) != 0) { - fdrop(oldfde->fde_file, td); + fdrop(oldfp, td); goto unlock; } break; case FDDUP_MUSTREPLACE: /* Target file descriptor must exist. */ if (fget_locked(fdp, new) == NULL) { - fdrop(oldfde->fde_file, td); + fdrop(oldfp, td); goto unlock; } break; @@ -948,7 +949,7 @@ error = racct_set_unlocked(p, RACCT_NOFILE, new + 1); if (error != 0) { error = EMFILE; - fdrop(oldfde->fde_file, td); + fdrop(oldfp, td); goto unlock; } } @@ -963,6 +964,12 @@ } KASSERT(old != new, ("new fd is same as old")); + + /* Refetch oldfde because the table may have grown and old one freed. */ + oldfde = &fdp->fd_ofiles[old]; + KASSERT(oldfp == oldfde->fde_file, + ("fdt_ofiles shift from growth observed at fd %d", + old)); newfde = &fdp->fd_ofiles[new]; delfp = newfde->fde_file;