> On Dec 30, 2011, at 12:44, Thomas David Rivers wrote:
> >
> > This frequently lulls C developers on MVS into believing the
> > runtime there checks for dereferencing NULL and does something
> > "meaningful" with it; or that, for example, strlen(NULL) returns
> > 0...  but nope - it's just luck.
> >
> Actually, not entirely.  It was mentioned on MVS-OE several
> years ago that many UNIX systems keep a 0 at location 00, and
> many C programmers have come to depend on this behavior, however
> incorrectly.  IBM got weary of problem reports, "But it works
> on systems X, Y, and Z" that many library routines that used
> to report "Invalid Pointer" were modified to substitute ""
> for NULL and proceed accordingly.
>
> -- gil
>

 Hmm - I can't think of a single UNIX implementation that
 does that by default; although I believe there are link-time
 options on Solaris/AIX and HP-UX and that will enable any number
 of facilities to cover-it-up; several of them requiring shared
 libraries.. but, the reader should check for himself.

 This is quickly verified by this small example:

   int
   main(int argc, char *argv[])
   {
      int *p;
      int i;

      p = 0x0;
      i = *p;
      return i;
   }

 which is a blatant dereference of NULL and does not involve
 possibility of a runtime check by a library function call.

 I've verified on several UNIXes (with the default compile+link
 options) that this does get an error, typically:

        Segmentation fault (core dumped)

 [I haven't yet tried it on AIX, I can do that when I return to
 the office... perhaps AIX allows the dereference to be similar
 to z/OS by default? I believe that may the case, but only for AIX...
 see below for z/OS discussion.  Is it possible that it's only AIX
 that adopted this approach for portability to/from z/OS?]

 And, I thought this instruction:

        L  1,0(0,0)

 on z/OS would not cause an ABEND... it would simply load the
 first 4 bytes of (virtual) memory starting a offset X'00000000'.

 And, I've run the example above on USS with the IBM compiler,
 here's the code it generated:

                           000006 |       *
                           000007 |       *     p = 0x0;
 000048  4110  0000        000007 |                 LA       r1,0
 00004C  5010  D098        000007 |                 ST       r1,p(,r13,152)
                           000008 |       *     i = *p;
 000050  58F0  1000        000008 |                 L        r15,(*)int(,r1,0)
 000054  50F0  D09C        000008 |                 ST       r15,i(,r13,156)
                           000009 |       *     return i;


 (compiled with simply 'cc -v')

 That rather clearly loads from address X'00000000'.  It runs
 without problem on z/OS, and demonstrates there is no runtime
 checking for dereference of NULL.  It must be the case that
 z/OS allows the dereference of NULL.

 Note that z/Linux does *not* allow this dereference, the same
 program executed there gets the typical "Segmentation fault".

 Thus, this is clearly not an artifact of the hardware, but an
 artifact of the operating system.

 This is why I say it is my understanding that most UNIX-based
 systems do not allow a dereference of NULL, but z/OS does; and
 why z/OS C developers are surprised when their programs don't
 work on other platforms.

 I would furthermore posit, that since a derefence of NULL causes no ABEND
 on z/OS, there is little chance that the developers of the z/OS
 runtime checked for it in the runtime functions.  That is, I doubt
 that strlen(), strcpy(), etc... actually check for a NULL pointer.
 Although, without an opportunity to see the source, that is
 simply a guess.

 The Dignus runtime does not check (often these functions are
 generated with an in-line expansion and even that in-line sequence
 of code does not check.)  Such a check would add to the runtime
 cost, when, should a program do it; it is in violation of the language
 rules... (your gun, your foot)

 However, the Dignus printf-formatting functions *do* check when
 a NULL is passed to a %s specifier.  In that case, the Dignus
 functions print the string "(NULL)" to indicate the error.  The
 IBM functions print a 'string' of whatever is in low core (which
 typically starts with a 0x00 byte, and there is simply "".)  The ANSI
 C standard is rather clear that both behaviors are allowed.
 That could be a source of distinction that is vexing to programmers,
 as the typical z/OS programmer would expect NULL passed to
 a %s printf-specifier to produce an empty string... while that
 is an invalid assumption.

 Given my ramblings above, is it possible the discussion on
 MVS-OE had it backwards, or were only speaking of AIX as
 the protypical UNIX?

        - Dave Rivers -

--
[email protected]                        Work: (919) 676-0847
Get your mainframe programming tools at http://www.dignus.com

Reply via email to