aj-mberg@dasys1.UUCP (Micha Berger) (07/19/89)
The header said it all, what is POSIX? micha -- Micha Berger "Always should [the child of] Adam have awe of G-d in secret and in public, admit the truth, and speak truth in his heart."
ast@cs.vu.nl (Andy Tanenbaum) (07/19/89)
In article <10284@dasys1.UUCP> aj-mberg@dasys1.UUCP (Micha Berger) writes: > what is POSIX? POSIX is the IEEE P1003 standard. It is an attempt to get rid of the the 4.3/5.3 split in the UNIX world and come to a single standard. What the standardization committee did was take all those features that were in Both 4.3 and 5.3 and put them in POSIX. Of course, that was basically V7. Ioctl and signals are different, and there is a little bit of new stuff, but semantically, it is moderately close to V7. That is why I like POSIX so much. It is real UNIX, stripped of all the barnacles that both AT&T and Berkeley have added to it. Andy Tanenbaum (ast@cs.vu.nl)
ast@cs.vu.nl (Andy Tanenbaum) (10/26/89)
I am beginning to get a little sick about the dosread.c again discussion.
At least the discussion about the PDP-11 MMU was technical, even though
somewhat irrelevant for this group. I interpret the DOS lovers/haters
discussion to mean that we have run out of material to talk about. Let me
inject some fresh material. For those people who don't have a POSIX
standard, here is what I believe to be a complete list of all the function
calls required by P1003.1. Run it off using tbl and troff. If somebody
wants to write tbl and troff for MINIX, by all means please do so.
For the uninitiated, POSIX defines a set of function calls that must be
available. Whether they are system calls are library calls is up to the
implementer. I, for example, intend to implement sigemptyset as the
folloing library routine:
sigemptyset(set)
sigset_t *set;
{
*set = 0;
}
I suspect there will be a lot of discussion of POSIX in the coming months.
The reason I suspect this is that I intend to generate some of it. If you
want to follow what is going on, order the P1003.1 standard from IEEE
by calling them at (201) 981-0060 in Piscatawy NJ. It costs $20 for IEEE
members and $36 for nonmembers. They take credit card phone orders.
I am also going to post the preliminary MINIX 2.0 (probably also 1.4b)
headers right now. This is the complete set. It is my hope that they
all conform to ANSI and POSIX. Fat chance. Will the language lawyers
please go over them and post comments. Then we can have philosophical
discussions about things like mandatory options (including time_t
in <sys/types.h>) and the like.
If you are itching to hack MINIX and learn about POSIX at the same time,
may I suggest a project: get the standard and write some POSIX test
programs. Test programs are an area where one cannot have too many.
In the shar file below is a sample test program, for P1003.1 Section 5.1.
I rather like this style, and would encourage others to use it. Note
that I also test for the error conditions required by the standard.
When running the test program, I found a gross bug in Doug Gwyn's directory
package. When you call opendir(), a DIR struct is
malloc'ed. This struct contains a buffer pointer. When you closedir(),
the buffer and the struct are returned. However, if you call closedir()
with a dirp that has already been closed, closedir() assumes that dirp
points to a valid DIR, finds the pointer to the buffer, and calls free()
to release the storage. To make a long story short, free() is not
enamoured of being called with essentially a random number as argument.
It makes its unhappiness known in an unpleasant way--by dumping core.
I have fixed the bug by putting a magic number in DIR, so all the calls
can see if the dirp points to something valid. Closedir() erases the
magic number (see _DIR_MAGIC in dirent.h). I will post the corrected
routines along with 1.4b.
If you don't like all the stupid underscores in the headers, may I
congratulate you on your good taste. Maybe we underscore-haters could
join X3J11 en masse and vote the underscore-lovers down.
Andy Tanenbaum (ast@cs.vu.nl)
: This is a shar archive. Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'posix.calls'
sed 's/^X//' > 'posix.calls' << '+ END-OF-FILE ''posix.calls'
X.tr _\(ru
X.PP
XBelow is a complete list of the POSIX functions (excluding the
XC library functions required by Chap. 8). A prototype and description
Xis given for each one.
XNext comes a phrase about the implementation. The designation "V1.4" means
Xthat the MINIX V1.4b version is pretty close. In no case is it exact however.
XThe last column tells whether the function is a system call (S) or a library
Xroutine that makes other system calls (L).
X.sp 2
X.TS
Xcenter allbox tab(;);
Xl l l l .
XPOSIX Chap. 3 Functions;Description;Implementation;SL
X_
Xpid_t fork();Fork;V1.4;S
Xint exec(...);Execl, execv, etc.;V1.4;S
Xpid_t wait(int *stat_loc);Wait for child;Just call waitpid();L
Xpid_t waitpid(pid_t pid, int *stat_loc, int options);Wait for child;New call;S
Xvoid _exit(int status);Terminate process;V1.4 exit();S
Xint kill(pid_t pid, int sig);Send a signal;Modified V1.4;S
Xint sigemptyset(sigset_t *set);Create signal set;New lib;L
Xint sigfillset(sigset_t *set);Create signal set;New lib;L
Xint sigaddset(sigset_t *set, int signo);Add sig to set;New lib;L
Xint sigdelset(sigset_t *set, int signo);Remove sig from set;New lib;L
Xint sigismember(sigset_t *set, int signo);Test for membership;New lib;L
Xint sigaction(int sig, struct sigaction *act, *oact);Replaces signal;New call;S
Xint sigprocmask(int how, sigset *set, *oset);Manipulate mask;New call;S
Xint sigpending(sigset_t *set);Inspect pending sigs;New call;S
Xint sigsuspend(sigset_t *sigmask);Replace sig mask;New call;S
Xunsigned int alarm(unsigned int sec);Set timer;V1.4;S
Xint pause();Suspend caller;V1.4;S
Xunsigned int sleep(int sleep);Sleep;Truly hairy lib;L
X.TE
X.sp
X.TS
Xcenter allbox tab(;);
Xl l l l .
XPOSIX Chap. 4 Functions;Description;Implementation;SL
X_
Xpid_t getpid();Get process id;V1.4;S
Xpid_t getppid();Get parent's id;New call;S
Xuid_t getuid();Get user id;V1.4;S
Xuid_t geteuid();Get effective user id;V1.4;S
Xgid_t getgid();Get group id;V1.4;S
Xgid_t getegid();Get effective group id;V1.4;S
Xint setuid(uid_t uid);Set uid;Modified V1.4;S
Xint setgid(gid_t gid);Set gid;Modified V1.4;S
Xint getgroups(int gidsetsize, gid_t grouplist[]);Get groups;No-op;L
Xchar *getlogin();Get login name;V1.4 lib;L
Xchar *cuserid(char *s);Get current user id;V1.4 lib;L
Xpid_t getpgrp();Get process group;New call;S
Xpid_t setsid();Set session id;New call;S
Xpid_t setpgid(pid_t pid, pid_t pgid);Set process group;New call;S
Xint uname(struct utsname *name);Get system id;New lib;L
Xtime_t time(time_t *loc);Get time since 1970;V1.4;S
Xclock_t times(struct tms *buffer);Get accounting;V1.4;S
Xchar *getenv(char *name);Search environment;V1.4 lib;L
Xchar *ctermid(char *s);Get controlling tty name;V1.4 lib;L
Xchar *ttyname(int fd);Get tty name;V1.4 lib;L
Xchar *isatty(int fd);See if fd is tty;V1.4 lib;L
Xlong sysconf(int name);Get config params;New lib;L
X.TE
X.bp
X.TS
Xcenter allbox tab(;);
Xl l l l .
XPOSIX Chap. 5 Functions;Description;Implementation;SL
X_
XDIR *opendir(char *dirname);Open a dir;Doug Gwynn's lib routine;L
Xstruct dirent *readdir(DIR *dirp);Read dir entry;Doug Gwynn's lib routine;L
Xvoid rewinddir(DIR *dirp);Rewind dir;Doug Gwynn's lib routine;L
Xint closedir(DIR *dirp);Close dir;Doug Gwynn's lib routine;L
Xint chdir(char *path);Change dir;V1.4 syscall;S
Xchar *getcwd(char *buf, int size);Get working dir;V1.4 lib routine;L
Xint open(char *path, int oflag, mode_t mode);Open a file;Modified V1.4;S
Xint creat(char *path, mode_t mode);Create file;Just call open();L
Xmode_t umask(mode_t cmask);Set file mask;V1.4;S
Xint link(char *path1, char *path2);Link file;V1.4;S
Xint mkdir(char *path, mode_t mode);Make dir;New call;S
Xint mkfifo(char *path, mode_t mode);Make FIFO;Use mknod();S
Xint unlink(char *path);Unlink file;V1.4;S
Xint rmdir(char *path);Remove dir;New call;S
Xint rename(char *old, char *new);Rename file;New call;S
Xint stat(char *path, struct stat *buf);Stat file;V1.4;S
Xint fstat(int fd, struct stat *buf);Stat file;V1.4;S
Xint access(char *path, int amode);Determine access;V1.4;S
Xint chmod(char *path, mode-t mode);Change mode;V1.4;S
Xint chown(char *path, uid_t owner, gid_t group);Change group;Modified V1.4;S
Xint utime(char *path, struct utimbuf *times);Set times;V1.4;S
Xlong pathconf(char *path, int name);Get values;Trivial lib;L
Xlong fpathconf(int fd, int name);Get values;Trivial lib;L
X.TE
X.sp 0.5
X.TS
Xcenter allbox tab(;);
Xl l l l .
XPOSIX Chap. 6 Functions;Description;Implementation;SL
X_
Xint pipe(int fd[]);Create pipe;V1.4;S
Xint dup(int fd);Duplicate file descr.;Lib call to fcntl;L
Xint dup2(int fd);Duplicate file descr.;Lib call to fcnl;L
Xint close(int fd);Close file;V1.4;S
Xint read(int fd, char *buf, unsigned nbyte);Read data;Modified V1.4;S
Xint write(int fd, char *buf, unsigned nbyte);Write data;Modified V1.4;S
Xint fcntl(int fd, int cmd, int arg);Misc. junk;New call;S
Xoff_t lseek(int fd, off_t offset, int whence);Seek;V1.4;S
X.TE
X.sp 0.5
X.TS
Xcenter allbox tab(;);
Xl l l l .
XPOSIX Chap. 7 Functions;Description;Implementation;SL
X_
Xspeed_t cfgetospeed(struct termios ptr);Get output speed;New call;S
Xint cfsetospeed(struct termios ptr, int speed);Set output speed;New call;S
Xspeed_t cfgetispeed(struct termios ptr);Get input speed;New call;S
Xint cfsetispeed(struct termios ptr, int speed);Set input speed;New call;S
Xint tcgetattr(int fd, struct termios ptr);Get tty attributes;New call;S
Xint tcsetattr(int fd, int act, struct termios ptr);Set tty attributes;New call;S
Xtcsendbreak(int fd, int duration);Send a break;New call;S
Xint tcdrain(int fd);Wait until output done;New call;S
Xint tcflush(int fd, int queue_selctor);Purge input/output;New call;S
Xint tcflow(int fd, int action);Start/stop tty line;New call;S
Xpid_t tcgetpgrp(int fd);Get process group;New call;S
Xint tcsetpgrp(int fd, pid_t pgrp_id);Set process group;New call;S
X.TE
+ END-OF-FILE posix.calls
chmod 'u=rw,g=r,o=r' 'posix.calls'
set `wc -c 'posix.calls'`
count=$1
case $count in
5700) :;;
*) echo 'Bad character count in ''posix.calls' >&2
echo 'Count should be 5700' >&2
esac
echo Extracting 'test20.c'
sed 's/^X//' > 'test20.c' << '+ END-OF-FILE ''test20.c'
X/* Test POSIX directory operations. */
X
X#include <sys/types.h>
X#include <dirent.h>
X#include <unistd.h>
X#include <errno.h>
X
X#define DIR_NULL (DIR *) NULL
X#define ITERATIONS 15
X#define MAX_FD 100 /* must be large enough to cause error */
X
Xint subtest, errct;
Xextern errno;
X
Xmain()
X{
X
X int i;
X
X sync();
X printf("Test 20 ");
X
X for (i = 0; i < ITERATIONS; i++) {
X test20a(); /* test for correct operation */
X test20b(); /* test general error handling */
X test20c(); /* test for EMFILE error */
X }
X if (errct == 0)
X printf("ok\n");
X else
X printf(" %d errors\n", errct);
X exit(0);
X}
X
Xtest20a()
X{
X/* Subtest 1. Correct operation */
X
X int f1, f2, f3, f4, f5;
X DIR *dirp;
X
X /* Remove any residue of previous tests. */
X subtest = 1;
X system("rm -rf foo");
X
X /* Create a directory foo with 5 files in it. */
X system("mkdir foo");
X if ( (f1 = creat("foo/f1", 0666)) < 0) e(1);
X if ( (f2 = creat("foo/f2", 0666)) < 0) e(2);
X if ( (f3 = creat("foo/f3", 0666)) < 0) e(3);
X if ( (f4 = creat("foo/f4", 0666)) < 0) e(4);
X if ( (f5 = creat("foo/f5", 0666)) < 0) e(5);
X
X /* Now remove 2 files to create holes in the directory. */
X if (unlink("foo/f2") < 0) e(6);
X if (unlink("foo/f4") < 0) e(7);
X
X /* Close the files. */
X close(f1);
X close(f2);
X close(f3);
X close(f4);
X close(f5);
X
X /* Open the directory. */
X dirp = opendir("./foo");
X if (dirp == DIR_NULL) e(6);
X
X /* Read the 5 files from it.
X checkdir(dirp, 2);
X
X /* Rewind dir and test again. */
X rewinddir(dirp);
X checkdir(dirp, 3);
X
X /* We're done. Close the directory stream. */
X if (closedir(dirp) < 0) e(7);
X
X /* Remove dir for next time. */
X system("rm -rf foo");
X}
X
Xcheckdir(dirp, t)
XDIR *dirp; /* poinrter to directory stream */
Xint t; /* subtest number to use */
X{
X
X int i, f1, f2, f3, f4, f5, dot, dotdot, subt;
X struct dirent *d;
X char *s;
X
X /* Save subtest number */
X subt = subtest;
X subtest = t;
X
X /* Clear the counters. */
X f1 = 0;
X f2 = 0;
X f3 = 0;
X f4 = 0;
X f5 = 0;
X dot = 0;
X dotdot = 0;
X
X /* Read the directory. It should contain 5 entries, ".", ".." and 3 files.*/
X for (i = 0; i < 5; i++) {
X d = readdir(dirp);
X if (d == (struct dirent *) NULL) {
X e(1);
X subtest = subt; /* restore subtest number */
X return;
X }
X s = d->d_name;
X if (strcmp(s, "." ) == 0) dot++;
X if (strcmp(s, "..") == 0) dotdot++;
X if (strcmp(s, "f1") == 0) f1++;
X if (strcmp(s, "f2") == 0) f2++;
X if (strcmp(s, "f3") == 0) f3++;
X if (strcmp(s, "f4") == 0) f4++;
X if (strcmp(s, "f5") == 0) f5++;
X }
X
X /* Check results. */
X d = readdir(dirp);
X if (d != (struct dirent *) NULL) e(2);
X if (f1 != 1 || f3 != 1 || f5 != 1) e(3);
X if (f2 != 0 || f4 != 0) e(4);
X if (dot != 1 || dotdot != 1) e(5);
X subtest = subt;
X return;
X}
X
X
Xtest20b()
X{
X/* Subtest 4. Test error handling. */
X
X int fd, fd2;
X DIR *dirp;
X
X subtest = 4;
X
X if (opendir("foo/xyz/---") != DIR_NULL) e(1);
X if (errno != ENOENT) e(2);
X if (system("mkdir foo") < 0) e(3);
X if (chmod("foo", 0) < 0) e(4);
X if (opendir("foo/xyz/--") != DIR_NULL) e(5);
X if (errno != EACCES) e(6);
X if (system("rmdir foo") < 0) e(7);
X if ( (fd = creat("abc", 0666)) < 0) e(8);
X if (close(fd) < 0) e(9);
X if (opendir("abc/xyz") != DIR_NULL) e(10);
X if (errno != ENOTDIR) e(11);
X if ( (dirp = opendir(".")) == DIR_NULL) e(12);
X if (closedir(dirp) != 0) e(13);
X if (closedir(dirp) >= 0) e(14);
X if (readdir(dirp) != (struct dirent *) NULL) e(15);
X if (errno != EBADF) e(16);
X if (readdir( (DIR *) -1) != (struct dirent *) NULL) e(17);
X if (errno != EBADF) e(18);
X
X}
X
X
Xtest20c()
X{
X/* Subtest 5. See what happens if we open too many directory streams. */
X
X int i, j;
X DIR *dirp[MAX_FD];
X
X subtest = 5;
X
X for (i = 0; i < MAX_FD; i++) {
X dirp[i] = opendir(".");
X if (dirp[i] == NULL) {
X /* We have hit the limit. */
X if (errno != EMFILE) e(1);
X for (j = 0; j < i; j++)
X if (closedir(dirp[j]) != 0) e(2); /* close */
X return;
X }
X }
X
X /* Control should never come here. This is an error. */
X e(3);
X for (i = 0; i < MAX_FD; i++) closedir(dirp[i]); /* don't check */
X}
X
X
Xe(n)
Xint n;
X{
X printf("\n\tSubtest %d, error %d, errno=%d ", subtest, n, errno);
X perror("");
X errct++;
X}
X
+ END-OF-FILE test20.c
chmod 'u=rw,g=r,o=r' 'test20.c'
set `wc -c 'test20.c'`
count=$1
case $count in
4163) :;;
*) echo 'Bad character count in ''test20.c' >&2
echo 'Count should be 4163' >&2
esac
exit 0
madd@world.std.com (jim frost) (10/26/89)
In article <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: |When running the test program, I found a gross bug in Doug Gwyn's directory |package. However, if you call closedir() |with a dirp that has already been closed, closedir() assumes that dirp |points to a valid DIR I'm not certain I'd call this a directory package bug, although an attempt to trap it is certainly a feature. GIGO and all. A legitimate closedir bug is something like the one in the SysV closedir. Paraphrased: closedir(dir) DIRP *dir; { free(dir); return(close(dir->dirf)); } |If you don't like all the stupid underscores in the headers, may I |congratulate you on your good taste. Maybe we underscore-haters could |join X3J11 en masse and vote the underscore-lovers down. I'd be happy to. It's kind of annoying to have to migrate up to that top row all the time. :-) Happy hacking, jim frost software tool & die madd@std.com
rsalz@bbn.com (Rich Salz) (10/27/89)
In <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) says he found a "gross bug" ross bug in Doug Gwyn's directory: "if you call closedir() with a dirp that has already been closed" the free inside closedir() will bomb. He then says he "fixed" it by putting a magic number which is checked, then cleared, by closedir(). Well gee, strcpy() can blow up if either parameter is a null pointer. Gonna fix that? fprintf("%d", 5) can blow up. Gonna fix that? The point is that you're if you call closedir() twice you've broken the rules. Don't do that, and don't slow down standard library routines by bullet-proofing that way. You just do a half-way, inconsistent job, that helps hide bugs when code is ported. BSD did NOT do the world a favor by making it legal to deference location zero -- ask anyone who's ported poor code from BSD to Sun, for example. As a minor point, the "fix" mentioned above isn't bulletproof, either. It is not impossible that I pass a garbage pointer into closedir() that just happens to point to some place with the same magic number. Please don't distribute these changes. /r$ -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.
ast@cs.vu.nl (Andy Tanenbaum) (10/27/89)
In article <1989Oct26.143100.4916@world.std.com> madd@world.UUCP (jim frost) writes: >In article <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: >|When running the test program, I found a gross bug in Doug Gwyn's directory >|package. However, if you call closedir() >|with a dirp that has already been closed, closedir() assumes that dirp >|points to a valid DIR > >I'm not certain I'd call this a directory package bug, Perhaps it wasn't a bug previously, but has to be regarded as a bug now because POSIX explicitly requires a call to closedir() with a rotten argument to return EBADF, not to crash, trap or do anything else. (See Sec. 5.1.2.4 of P1003.1). Andy Tanenbaum (ast@cs.vu.nl)
michaelb@vms.macc.wisc.edu (MICHAEL BLOXHAM) (10/27/89)
In article <3819@ast.cs.vu.nl>, ast@cs.vu.nl (Andy Tanenbaum) writes... > >I am beginning to get a little sick about the dosread.c again discussion. >At least the discussion about the PDP-11 MMU was technical, even though >somewhat irrelevant for this group. I interpret the DOS lovers/haters The reason for the volume of the dosread.c discussion is that the original posting was cross-posted to comp.sys.ibm.pc. So everyone there is getting bent outta shape over AST's reply which also got cross-posted, probably unknowingly. This reply of no DOS interest to a mainly DOS related group caused a lot of eye raising. so much for the obvious, mike
truesdel@sun217..nas.nasa.gov (David A. Truesdell) (10/27/89)
ast@cs.vu.nl (Andy Tanenbaum) writes: >Perhaps it wasn't a bug previously, but has to be regarded as a bug now >because POSIX explicitly requires a call to closedir() with a rotten >argument to return EBADF, not to crash, trap or do anything else. (See >Sec. 5.1.2.4 of P1003.1). I bet to differ! I consider this to be pointing out a bug in the implementation of free(). Calling free(), with a grabage pointer, shouldn't result in a trap either. It shouldn't be layed at the feet of a portable library package to work around possible bugs in the underlying environment. A call to free() should (IMHO) result in either the storage being added to the free pool, if a valid looking header is found, or no action at all if garbage is presented. T.T.F.N., dave truesdell (truesdel@prandtl.nas.nasa.gov)
rsalz@bbn.com (Rich Salz) (10/27/89)
In article <3819@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: >with a dirp that has already been closed, closedir() assumes that dirp >points to a valid DIR Both Jim Frost (<1989Oct26.143100.4916@world.std.com>) and I (<something>) don't think this is a bug. In <3842@math.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: >Perhaps it wasn't a bug previously, but has to be regarded as a bug now >because POSIX explicitly requires a call to closedir() with a rotten >argument to return EBADF, not to crash, trap or do anything else. (See >Sec. 5.1.2.4 of P1003.1). If closedir() is not implemented as a syscall, then the only portable way to handle this is to keep a list of everything you ever opendir'd, and a flag as to whether it's still valid or not. Magic numbers just ain't foolproof. Posix blew it on this one; they should have defined it to be undefined action. /r$ -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.
ast@cs.vu.nl (Andy Tanenbaum) (10/28/89)
In article <3600@amelia.nas.nasa.gov> truesdel@sun217..nas.nasa.gov (David A. Truesdell) writes: >I bet to differ! I consider this to be pointing out a bug in the implementation >of free(). Calling free(), with a grabage pointer, shouldn't result in a >trap either. It shouldn't be layed at the feet of a portable library package >to work around possible bugs in the underlying environment. I disagree. A proper, portable library package should not make invalid calls to other library routines in the expectation that they will detect their bad arguments and give a polite reply. If you maintain that the called library routine (free) should check for bad arguments, then the directory package should also check for bad arguments. As a library implementer you can hardly say "Everybody else should check for bad arguments are complain when found, but I don't have to check." Andy Tanenbaum (ast@cs.vu.nl)
ast@cs.vu.nl (Andy Tanenbaum) (10/28/89)
In article <2091@prune.bbn.com> rsalz@bbn.com (Rich Salz) writes: >If closedir() is not implemented as a syscall, then the only portable >way to handle this is to keep a list of everything you ever opendir'd, >and a flag as to whether it's still valid or not. No. It is sufficient to keep a list of all the ones that are still open. When someone does a close, you check the list and if it is not on it, you return EBADF. My quickie solution is only 65535/65536-ths correct, but I find the code too hairy to change in any serious way. >Posix blew it on this one; they should have defined it to be undefined I disagree. I think every incorrect call should return an error and the standard should specify which error it is, to allow applications to test for that specific error. In almost all other parts of the standard they specified the error returns, so why not here. Andy Tanenbaum (ast@cs.vu.nl)
johnz@grapevine.uucp (John Zolnowsky ext. 33230) (10/28/89)
In article <2091@prune.bbn.com>, rsalz@bbn.com (Rich Salz) writes: > In <3842@math.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: > >Perhaps it wasn't a bug previously, but has to be regarded as a bug now > >because POSIX explicitly requires a call to closedir() with a rotten > >argument to return EBADF, not to crash, trap or do anything else. (See > >Sec. 5.1.2.4 of P1003.1). > > If closedir() is not implemented as a syscall, then the only portable > way to handle this is to keep a list of everything you ever opendir'd, > and a flag as to whether it's still valid or not. > > Posix blew it on this one; they should have defined it to be undefined > action. POSIX is full of "legalese" for these cases. The EBADF case mentioned above, for instance, is prefaced by the conditional: "For each of the following conditions, *when* [emphasis added -JZ] the condition is detected, the closedir() function shall return -1 and set errno ..." Section 2.5 Error Numbers further clarifies this in the fourth paragraph: "Implementations may support additional errors not included in this list, may generate errors in this list under circumstances other than those described here, or may contain extensions or *limitations* [emphasis added -JZ] that prevent some errors from occurring." POSIX defines the behavior of a conforming program. A program which closedirs a DIR pointer twice is non-conforming, and the behavior of the implementation need not be meaningful, useful, or even helpful. -JZ ---------------------------------------------------------------------- John Zolnowsky johnz@EBay.Sun.COM or ...!sun!johnz
dal@syntel.mn.org (Dale Schumacher) (10/28/89)
truesdel@sun217..nas.nasa.gov (David A. Truesdell) writes: |ast@cs.vu.nl (Andy Tanenbaum) writes: |>Perhaps it wasn't a bug previously, but has to be regarded as a bug now |>because POSIX explicitly requires a call to closedir() with a rotten |>argument to return EBADF, not to crash, trap or do anything else. (See |>Sec. 5.1.2.4 of P1003.1). | |I bet to differ! I consider this to be pointing out a bug in the implementation |of free(). Calling free(), with a grabage pointer, shouldn't result in a |trap either. It shouldn't be layed at the feet of a portable library package |to work around possible bugs in the underlying environment. | |A call to free() should (IMHO) result in either the storage being added |to the free pool, if a valid looking header is found, or no action at all |if garbage is presented. Sorry, but this is not free()'s job. Section 4.10.3.2, describing the 'free' function, states: The 'free' function causes the space pointed to by 'ptr' to be deallocated, that is, made available for further allocation. If 'ptr' is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by the 'calloc', 'malloc', or 'realloc' function, or if the space has been deallocated by a call to 'free' or 'realloc', the behaviour is undefined. "Undefined" behaviour means it can do ANYTHING if that situation occurs. Now that we have standards (or nearly so, in the case of C), personal opinions are moot. Also, P1003.1 says about closedir(): For each of the following conditions, when the condition is detected, the closedir() function shall return -1 and set 'errno' to the corresponding value: [EBADF] The 'dirp' argument does not refer to an open directory stream. Thus the bug is really a bug, and Doug probably already is aware of it, though perhaps Andy should send him a note to be sure. \\ / Dale Schumacher 399 Beacon Ave. \\ / (alias: Dalnefre') St. Paul, MN 55104-3527 >< ...umn-cs!midgard.mn.org!syntel!dal United States of America / \\ "What is wanted is not the will to believe, but the will to find out, / \\ which is the exact opposite." -Bertrand Russell
peter@ficc.uu.net (Peter da Silva) (10/28/89)
In article <4128@ast.cs.vu.nl> ast@cs.vu.nl (Andy Tanenbaum) writes: > If you maintain that the > called library routine (free) should check for bad arguments, then the > directory package should also check for bad arguments. Malloc/free are normally expected to track allocated memory, so it is reasonable to expect them to be able to check their arguments... they already have the information they need. A directory package doesn't, so you eithet have to maintain a list of allocated chunks, duplicating free's work, or go to an unreliable system like a flag word. Or pre-allocate the structures and use descriptors. An argument-checking library is a good idea. But the amount of overhead needed to do this right is prohibitive, and doing it wrong gives a false sense of security. A production library should not even try unless the right set of checks are cheap... like in malloc/free. It's not something for POSIX to specify, and in fact they don't specify it. They merely say that *when an error is detected* the error code should be EBADF. -- `-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.hackercorp.com>. 'U` -------------- +1 713 274 5180. "That particular mistake will not be repeated. There are plenty of mistakes left that have not yet been used." -- Andy Tanenbaum (ast@cs.vu.nl)
peter@ficc.uu.net (Peter da Silva) (10/29/89)
In article <092789A7523@syntel.mn.org> dal@syntel.mn.org (Dale Schumacher) writes: ! For each of the following conditions, WHEN THE CONDITION IS ! DETECTED, the closedir() function shall return -1 and set > 'errno' to the corresponding value: > [EBADF] The 'dirp' argument does not refer to an open directory > stream. [emphasis mine -- pds] And if the condition is not detected? -- `-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.hackercorp.com>. 'U` -------------- +1 713 274 5180. "That particular mistake will not be repeated. There are plenty of mistakes left that have not yet been used." -- Andy Tanenbaum (ast@cs.vu.nl)
ast@cs.vu.nl (Andy Tanenbaum) (10/30/89)
In article <34633@grapevine.uucp> johnz@grapevine.uucp (John Zolnowsky ext. 33230) writes: >POSIX is full of "legalese" for these cases. The EBADF case mentioned >above, for instance, is prefaced by the conditional: > "For each of the following conditions, *when* [emphasis added -JZ] > the condition is detected, the closedir() function shall return > -1 and set errno ..." Thanks you for your explanation. I had assumed that "when" meant "at the time that" rather than "if," but you may well be right. I only hope that the guys making conformance tests understand this. The little test program I posted actually checks for it. If you are right, the test program is overzealous. Andy Tanenbaum (ast@cs.vu.nl)
henry@utzoo.uucp (Henry Spencer) (10/31/89)
In article <6716@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: >! For each of the following conditions, WHEN THE CONDITION IS >! DETECTED, the closedir() function shall return -1 and set >> 'errno' ... > >And if the condition is not detected? Then the ball is in the implementor's court, and all bets are off. -- A bit of tolerance is worth a | Henry Spencer at U of Toronto Zoology megabyte of flaming. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
truesdel@sun217..nas.nasa.gov (David A. Truesdell) (10/31/89)
In comp.os.minix you write: >truesdel@sun217..nas.nasa.gov (David A. Truesdell) writes: >Sorry, but this is not free()'s job. Section 4.10.3.2, describing the >'free' function, states: > > . . . if the space has > been deallocated by a call to 'free' or 'realloc', the behaviour > is undefined. > >"Undefined" behaviour means it can do ANYTHING if that situation occurs. >Now that we have standards (or nearly so, in the case of C), personal >opinions are moot. True, "Undefined" does mean you could do anything, but there is something to be said for the "Principle of Least Astonishment". Would you use a system on which the "undefined" behaviour meant "destroy all data on disk"? I sure wouldn't, but it is permitted by the standard. But then, I don't like library routines dumping core, either. Guess I'm just too conservative. T.T.F.N., dave truesdell (truesdel@prandtl.nas.nasa.gov)
cechew@bruce.OZ (Earl Chew) (11/13/89)
From article <12288@fluke.COM>, by dcd@tc.fluke.COM (David Dyck): > "Std 1003.3 - Draft 7.0 TEST METHODS for MEASURING CONFORMANCE to POSIX 1003.1" > (NOTE: this is still in DRAFT form) > and looked up the documentation for closedir that ast mentioned October 25th. > It states (under section 5.1.2.4 Errors) > > "On a call to closedir(dirp) when the dirp argument does not refer to an open > directory streem, shall return a value of -1 and set "errno" to {EBADF}." This is in direct contradiction to Std 1003.1-1988 Sec B.5.1.2: "Since the strcutre and buffer allocation, if any, for directory operations are defined by the implementation, the standard imposes no portability requirements for erroneous program constructs, erroneous data, or the use of indeterminate values such as the use or referencing of a dirp value or a dirent structure value after a directory stream has been closed or after a fork() or one of the exec function calls." The wording *very* clear on this point. Furthermore, Std 1003.1-1988 Sec 5.1.1.2: "If the dirp argument passed to any of these functions does not refer to a currently-open directory stream, the effect is undefined." Thus the implementation (Minix) can do whatever it likes (ie check or not check). Earl -- Earl Chew, Dept of Computer Science, Monash University, Australia 3168 ARPA: cechew%bruce.cs.monash.oz.au@uunet.uu.net ACS : cechew@bruce.oz ----------------------------------------------------------------------