Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!decvax!tektronix!hplabs!hpda!hpisoa2!hpitg!ccird2!rb@ccird2 From: rb@ccird2 Newsgroups: net.lang.c Subject: Re: varargs Message-ID: <792@ccird2> Date: Fri, 25-Apr-86 01:11:00 EDT Article-I.D.: ccird2.792 Posted: Fri Apr 25 01:11:00 1986 Date-Received: Tue, 13-May-86 01:44:56 EDT References: <293@usc-obero> Lines: 85 In article <5302@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes: >> I have always heard that varargs is not very portable. Is this really >> true? If you know of any machine that is running 4.X BSD, System III/V, >> Xenix or any other real unix that doesn't support varargs, please let >> me know. > >If you find any machine with a sensible architecture that cannot >be made to support varargs, I would greatly like to hear about it. > The concern about about varargs is brought up in "Software Tools" by Kernigan and Plauger. The main concern is that certain systems and languages have the caller push the arguments, and have the callee destroy them when they are finished. This is common practice in Fortran and Pascal. The big concern with C is that there might be a compiler out there which has C/Pascal|Fortran compatibility. Since these compilers seem to be the exception rather than the rule, and newer versions of these languages are tending to follow C conventions, this is not likely to be a problem for *most* environments. I have heard that there are a few "peculiar" compilers available for the Atari ST, Mac, and Amiga, which, although not "kosher", CAN support most varargs situations. The problems that can occur are "intelligent" compilers which put arguments directly into registers rather than on the stack. Appearantly, this can be a real problem if you wish to "intercept" a system call at the application side. Why do so many of the micro operating systems insist on putting arguments in registers!!!. Even MS-DOS expects arguments in registers rather than on the stack. The C frame is a more sensible archetecture, but not the only one. Since you specifically asked about UNIX based systems, you can be relatively unconcerned. There are non-portable ways to USE varargs. The classic is to put a long indicator into the "format argument" and pass an int. Do this with a couple of arguments where ints are 16 bits, and longs are 32 bits, and you will return to "never never land". The normal usages (printf, scanf,...) aren't usually a problem, but there are a few "mix and match" functions using varargs which selectively mix and match various modifiable stack addresses, and will "core dump" the whole system. try this: (comments are for 16 bit ints, 32 bit longs, 32 bit pointers). main() { /* top of frame = return address */ int i; long l; scanf("%d %d",&i); /* second argument missing, clobbers frame */ scanf("%d",i); /* cute "poke" of i, can demolish code or core dump */ scanf("%ld",&i); /* extra 16 bits is usually frame pointer or return address */ scanf("%d",l); /* 16 bits of "garbage" plus your number possibly munged beyond recognition due to byte ordering */ } Lint will pass it, assuming printf is declared /*VARARGS*/, and the compiler won't even sneeze. But running it will give you "buss error core dumped" or something equally nasty. This is one of the few areas where lint will not protect you. Anyone figured out a syntax checker for these functions? Of course, you should use a syntax checker for any of these functions. Another cute trick I've seen is using varargs to pass integers to functions which assign to pointers. Such as: main() { int read(); init(0x20L,&read); /* set exception vector */ } /*VARARGS*/ init(a,b) char **a,*b,**i; { *a=b; /* poke absolute value with a valid address */ } This is the ultimate in unportability, but is frequently "hidden" in "hostile" PC programs, typically to mount new device drivers and remove them when the code is complete. Just try plugging one of these into unix unmodified :-).