[comp.unix.aux] stat

jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) (09/15/90)

Well... if I do the following, lstat() doesn't work:

	struct stat *sbuf;
	lstat("/unix", sbuf);

But this DOES:

	struct stat sbuf;
	lstat("/unix", &sbuf);

It looks like in case #1, sbuf is pointing somewhere dangerous and when lstat
is called, memory is destroyed... 
--
=======================================================================
#include <std/disclaimer.h>
                                 =:^)
           Jim Jagielski                    NASA/GSFC, Code 711.1
     jim@jagmac2.gsfc.nasa.gov               Greenbelt, MD 20771

"Kilimanjaro is a pretty tricky climb. Most of it's up, until you reach
 the very, very top, and then it tends to slope away rather sharply."

dyer@spdcc.COM (Steve Dyer) (09/15/90)

In article <3422@dftsrv.gsfc.nasa.gov> jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) writes:
]Well... if I do the following, lstat() doesn't work:
]	struct stat *sbuf;
]	lstat("/unix", sbuf);
]But this DOES:
]	struct stat sbuf;
]	lstat("/unix", &sbuf);
]
]It looks like in case #1, sbuf is pointing somewhere dangerous and when lstat
]is called, memory is destroyed... 

OK, so where's the bug?  You've not understood the C language.
Just where do you think sbuf is pointing to in the first example?
If you don't assign a value to a variable, how can you expect to
use its value as something meaningful?

-- 
Steve Dyer
dyer@ursa-major.spdcc.com aka {ima,harvard,rayssd,linus,m2c}!spdcc!dyer
dyer@arktouros.mit.edu, dyer@hstbme.mit.edu

liam@cs.qmw.ac.uk (William Roberts) (09/17/90)

In <4038@ursa-major.SPDCC.COM> dyer@spdcc.COM (Steve Dyer) writes:

>In article <3422@dftsrv.gsfc.nasa.gov> jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) writes:
>]Well... if I do the following, lstat() doesn't work:
>]	struct stat *sbuf;
>]	lstat("/unix", sbuf);
>]But this DOES:
>]	struct stat sbuf;
>]	lstat("/unix", &sbuf);
>]
>]It looks like in case #1, sbuf is pointing somewhere dangerous and when lstat
>]is called, memory is destroyed... 

>OK, so where's the bug?  You've not understood the C language.
>Just where do you think sbuf is pointing to in the first example?
>If you don't assign a value to a variable, how can you expect to
>use its value as something meaningful?

Or, slightly less harshly, you have some further nuances to learn about how
to read the UNIX section2 & 3 manual pages.

In particular, when you see pointers being used you must ask yourself
"Who is allocating the memory for this?" - in the case of pointers
passed as arguments, the answers is ALWAYS that the caller allocates the
memory since C uses call by value. When you see pointers to pointer as
arguments, or pointers as return values then there is a possibility that 
the called routine will do the memory allocation (e.g. getpwuid).

True system calls ALWAYS use pointers (because they are small and easy to
pass into the kernel) and ALWAYS require the user process to provide the
memory. 
-- 

William Roberts                 ARPA: liam@cs.qmw.ac.uk
Queen Mary & Westfield College  UUCP: liam@qmw-cs.UUCP
Mile End Road                   AppleLink: UK0087
LONDON, E1 4NS, UK              Tel:  071-975 5250 (Fax: 081-980 6533)

jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) (09/17/90)

In article <4038@ursa-major.SPDCC.COM> dyer@ursa-major.spdcc.COM (Steve Dyer) writes:
>In article <3422@dftsrv.gsfc.nasa.gov> jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) writes:
>]Well... if I do the following, lstat() doesn't work:
>]	struct stat *sbuf;
>]	lstat("/unix", sbuf);
>]But this DOES:
>]	struct stat sbuf;
>]	lstat("/unix", &sbuf);
>]
>]It looks like in case #1, sbuf is pointing somewhere dangerous and when lstat
>]is called, memory is destroyed... 
>
>OK, so where's the bug?  You've not understood the C language.
>Just where do you think sbuf is pointing to in the first example?
>If you don't assign a value to a variable, how can you expect to
>use its value as something meaningful?
>

In the 1st case, before the call, sbuf is set to NULL, thus ensuring that it
points to nothing, so my comment that it is pointing somewhere dangerous is
wrong (this setting of sbuf IS done in my program but was NOT included in
my posting... sorry).

The following WILL work (although it may NOT be portable and is NOT mentioned
in K&R):

	int *pint;
	pint = NULL;
	*pint = 10;

Now some C compilers (such as GreenHills and Vax-C) will accept lstat("/unix",
sbuf) and some won't. ALL will accept lstat("/unix",&sbuf) (assuming, of
course, that sbuf is defined correctly, 'natch). As was mentioned in a mail
message to me, some compilers may push a pointer to the struct in both cases,
(although this does NOT adhere to the X3J11 standard, which says that when
a structure is passed, the function gets an IMAGE of the structure). Therefore,
in the compilers that DO accept this, the function is either getting a pointer
or else the original structure. (observe that lstat expects a pointer to
a struct)

In any case, the second method (passing &sbuf) IS portable and is standard.
This is NOT, however, picked up by lint...

PS: This program was a port from VaxC, which ran it with no problem. It was
    and old piece of code which I did very quick-and-dry...

PPS:  I understand C quite well thank you... that is, when my brain isn't
      mush (which lately seems QUITE often :)
--
=======================================================================
#include <std/disclaimer.h>
                                 =:^)
           Jim Jagielski                    NASA/GSFC, Code 711.1
     jim@jagmac2.gsfc.nasa.gov               Greenbelt, MD 20771

"Kilimanjaro is a pretty tricky climb. Most of it's up, until you reach
 the very, very top, and then it tends to slope away rather sharply."

dyer@spdcc.COM (Steve Dyer) (09/17/90)

In article <3430@dftsrv.gsfc.nasa.gov> jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) writes:
>In the 1st case, before the call, sbuf is set to NULL, thus ensuring that it
>points to nothing, so my comment that it is pointing somewhere dangerous is
>wrong (this setting of sbuf IS done in my program but was NOT included in
>my posting... sorry).

Sigh.  You were a Pascal programmer in a previous life, I'll bet.
Um, it doens't point to nothing, it points to the memory location pointed
to by NULL.  This is usually location 0.

>The following WILL work (although it may NOT be portable and is NOT mentioned
>in K&R):
>
>	int *pint;
>	pint = NULL;
>	*pint = 10;

K&R or ANSI C don't prevent you from writing incorrect programs.
Unless you have explicit control over the loading of your program (say,
under an embedded system), and you KNOW that memory starting at location
0 (and going on for however long) is a valid destination, you simply
can't say anything whatsoever about whether this code fragment works.
You might as well be arguing that the following works:

	int *pint;
	pint = 476;
	*pint = 10;

Now, some architectures have location 0 mapped into a user's process
space as writable, and will gleefully allow you to overwrite whatever
is there.  On such architectures, location 0 frequently points to
once-only startup code, so since you never re-execute the now corrupted
machine code, you'll never notice the problem.  More modern
architectures make such code segments read-only and sharable to begin
with, so such an attempt to overwrite the segment will fail.  Even in
architectures where location 0 points to the user's data space, such an
assignment (or the call to stat/lstat) holds the possibility of
corrupting whatever the loader decided to place there.  Such
architectures (like the PDP-11 I&D machines) always reserve the first
word of the data segment which starts at 0 so that no variable address
would have the value 0 (that is, to insure that &var will never equal
NULL).  On such architectures, your example above would "succeed", but
the call to stat/lstat would still corrupt additional memory because
the system call would attempt to overwrite sizeof(struct stat) bytes
and not the sizeof(int) bytes in your example above.  It might not
cause an exception, but that doesn't mean that it's correct in any
sense of the word.  Presumably you had some data stored in those
subsequent memory locations which is now trash.

>Now some C compilers (such as GreenHills and Vax-C) will accept lstat("/unix",
>sbuf) and some won't. ALL will accept lstat("/unix",&sbuf) (assuming, of
>course, that sbuf is defined correctly, 'natch). As was mentioned in a mail
>message to me, some compilers may push a pointer to the struct in both cases,
>(although this does NOT adhere to the X3J11 standard, which says that when
>a structure is passed, the function gets an IMAGE of the structure). Therefore,
>in the compilers that DO accept this, the function is either getting a pointer
>or else the original structure. (observe that lstat expects a pointer to
>a struct)

This is not a standards issue.  I don't see anywhere in your examples:

      struct stat *sbuf;
      lstat("/unix", sbuf);
versus
      struct stat sbuf;
      lstat("/unix", &sbuf);

where the issue of compilers enters in.  ANY compiler should accept either
of these, and in both examples, there is no confusion about what it should
do.  Issues of structure passing and how it's implemented are not relevant
here because in both cases you're not passing structures, you're passing
a pointer.  It just happens that the first example is an uninitialized pointer
and the second points to something we KNOW we own.

There is a third possibility which you did not present as an example
(but which I believe you are confusing things with), namely:

      struct stat sbuf;
      lstat("/unix", sbuf);

Now, this is simply wrong because most system calls deal in pointers
or other scalar types, and not structures passed by value.  It's
possibly that a compiler which implements structure passing by
passing pointers would cause this example to "work", but it seems
irrelevant to me, and incorrect for entirely different reasons than the
ones you are trying to propose.

>In any case, the second method (passing &sbuf) IS portable and is standard.
>This is NOT, however, picked up by lint...

Most lints would say "sbuf may be used before set" in your first example
IFF you didn't initialize it.  But if you DID initialize it, even if
you initialized it to NULL, lint would no longer catch it.  lint carries
no semantics which tells it that some initialization values are OK and
others aren't.

>PS: This program was a port from VaxC, which ran it with no problem. It was
>    and old piece of code which I did very quick-and-dry...

So what?  The VAX is one of the architectures which allows you to trash
location 0.

>PPS:  I understand C quite well thank you... 

It doesn't seem so.

I would be very wary of taking a device driver written by someone who
exhibits the kind of misunderstanding of pointers which you have here.
This is not a personal dig, just a reasonable observation.

-- 
Steve Dyer
dyer@ursa-major.spdcc.com aka {ima,harvard,rayssd,linus,m2c}!spdcc!dyer
dyer@arktouros.mit.edu, dyer@hstbme.mit.edu

jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) (09/18/90)

In article <4062@ursa-major.SPDCC.COM> dyer@ursa-major.spdcc.com.spdcc.COM (Steve Dyer) writes:
>
>>PPS:  I understand C quite well thank you... 
>
>It doesn't seem so.
>
>I would be very wary of taking a device driver written by someone who
>exhibits the kind of misunderstanding of pointers which you have here.
>This is not a personal dig, just a reasonable observation.
>
>-- 

FLAME ON:	Okay. so it was a friday and  I was tired and I wrote a posting
  before I stopped to see what the hell I was writing. True, I was trying to
  save face with all this crap about compilers and so forth. However, these
  were observations from myself, others and assembler code from 3 different
  compilers running through this self same code. Some compilers WON'T let
  you pass structures to functions as is canon K&R. Some compilers WILL,
  when you tell the pointer to point to NULL, have the pointer point to
  space which is big enuff for whatever the pointer is a pointer to. This is
  a fact. What the problem was was that I was looking at the code without
  THINKING about the code... I guess someone as perfect as you has never done
  THAT before. As far as you thinking I don't understand C, well, I beg to
  differ. Everyone has off days with C and can't recall what they wrote or
  what they mean, except of course yourself. I've written a bunch of C code,
  dude and it hasn't been all 100% perfect, but no one's is, except yours,
  of course.

  I can't wait till YOU make a mistake, so I can knock your ass down!

  PS: What device drivers are you talking about asshole? The EtherPortII
      drivers???????? THEY are from Kinetics... I simply tared them together
      and made them available to people... oh yeah, I DID happen to change
      a "BNET" to "bnet_dr" in the install script... Hope to hell I can
      use vi to your satisfaction! I could go on about you thinking that I
      wrote these drivers as being a stupid mistake, but I won't.

FLAME OFF:

Now, we return you to your regularly scheduled group...


--
=======================================================================
#include <std/disclaimer.h>
                                 =:^)
           Jim Jagielski                    NASA/GSFC, Code 711.1
     jim@jagmac2.gsfc.nasa.gov               Greenbelt, MD 20771

"Kilimanjaro is a pretty tricky climb. Most of it's up, until you reach
 the very, very top, and then it tends to slope away rather sharply."

liam@cs.qmw.ac.uk (William Roberts) (09/21/90)

In <3434@dftsrv.gsfc.nasa.gov> jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) writes:

>In article <4062@ursa-major.SPDCC.COM> dyer@ursa-major.spdcc.com.spdcc.COM (Steve Dyer) writes:
>>
>  Some compilers WON'T let
>  you pass structures to functions as is canon K&R.

True, but not particularly relevant. Such a compiler should
be associated with a version of lint that also insists on this, and
none of your examples did this anyway.

>  Some compilers WILL,
>  when you tell the pointer to point to NULL, have the pointer point to
>  space which is big enuff for whatever the pointer is a pointer to. This is
>  a fact.

Hang on a minute - name one such compiler!  You were the one who started
talking about "canon K&R" and XJwhatever committee numbers.

>  What the problem was was that I was looking at the code without
>  THINKING about the code... I guess someone as perfect as you has never done
>  THAT before. As far as you thinking I don't understand C, well, I beg to
>  differ. Everyone has off days with C and can't recall what they wrote or
>  what they mean, except of course yourself. I've written a bunch of C code,
>  dude and it hasn't been all 100% perfect, but no one's is, except yours,
>  of course.

Your making the EtherPort II stuff available is appreciated (I may soon
have something to add to your distribution - we have 50 of the old
EtherPort II cards so I am putting work into making they coexist with
A/UX 2.0 as well as possible).

Your flame about the mild criticisms your pointer-confusion has earned
is wildly out of proportion. You cannot both quote ANSI documents AND
say that "some compilers do ***horrid thing omitted***". 

Do you now accept that

1) the stat and lstat functions require a pointer to a statbuf structure
2) the stat and lstat functions don't do memory allocation for that structure
3) NULL is not a good choice of random address for a structure
4) You should be using &statbuf regardless of the fact that some 
   compiler/machine/architecture combinations let you get away with
   what you were doing before.

Making mistakes is forgiveable - insisting that they aren't mistakes is not.
-- 

William Roberts                 ARPA: liam@cs.qmw.ac.uk
Queen Mary & Westfield College  UUCP: liam@qmw-cs.UUCP
Mile End Road                   AppleLink: UK0087
LONDON, E1 4NS, UK              Tel:  071-975 5250 (Fax: 081-980 6533)

jim@jagmac2.gsfc.nasa.gov (Jim Jagielski) (09/23/90)

In article <2842@sequent.cs.qmw.ac.uk> liam@cs.qmw.ac.uk (William Roberts) writes:
>Do you now accept that
>
>1) the stat and lstat functions require a pointer to a statbuf structure
>2) the stat and lstat functions don't do memory allocation for that structure
>3) NULL is not a good choice of random address for a structure
>4) You should be using &statbuf regardless of the fact that some 
>   compiler/machine/architecture combinations let you get away with
>   what you were doing before.
>

As I wrote to Steve, yes I DID make a major mistake: 1st by passing the wrong
thing to stat and lstat and secondly NOT accepting the obvious reason for
the mistake... that the reason it DIDN'T work with cc and gcc is because stuff
was getting crunched since the pointer either pointed somewhere unknown or to
NULL (0). That is in essense what the entire thing was about... My other
comments about how stuff was being changed by different compilers was really
not appropriate, since even if it DID work with some other compilers, that
still doesn't affect the fact that the code was plain and simple WRONG.

The only thing that reall upset me was the comment concerning my knowledge of
C and that's what caused my flame... a bruised ego is a dangerous thing and
I am sorry for that. Everyone makes mistakes and I just didn't want a stupid
one to give the impression that I don't know C (although at the time, maybe
my mind was such mush that I didn't even know my name :).

Anyway, I hope all this is over with. I made my peace and apologies to Steve
and appreciate all his ( and everyone else's) comments and illumination.

The moral is: Think before you act... I gotta start doing that MORE!
--
=======================================================================
#include <std/disclaimer.h>
                                 =:^)
           Jim Jagielski                    NASA/GSFC, Code 711.1
     jim@jagmac2.gsfc.nasa.gov               Greenbelt, MD 20771

"Kilimanjaro is a pretty tricky climb. Most of it's up, until you reach
 the very, very top, and then it tends to slope away rather sharply."