Thank you for making clear that the different behaviour depends on the operating
system, not on the hardware.
Some slightly off-topic remarks:
I've seen the "(null)" output on NULL string pointers on printf with other
compilers, too (maybe Windoze, but I don't recall - no segmentation in this
case, that is, printf etc. must have checked before using the pointer)
and:
when de-referencing a pointer directly, you have no choice; if the compiler
doesn't include checks - which it normally doesn't for performance reasons - you
will have segmentation faults (called 0C4 on z/OS), but not with read access on
the prefix system area (low storage) on z/OS, because that's allowed on this
system.
But with runtime routines like printf etc., it's totally different. But even
there, the behaviour is different on the various platforms. I'm not sure, for
example, if a NULL pointer for the FILE descriptors on functions like fgets or
fprintf etc. is tolerated or not. Some runtimes check it and simply do nothing,
if the FILE pointer is null, and others (I believe) crash. But I'm not sure; I
only believe to recall that I already had such problems when porting C
applications (I work on many different platforms and often move C code from
Windows and Unixen to z/OS and the other way round).
Kind regards
Bernd
Am 02.01.2012 00:48, schrieb T.R.:
>> On Dec 30, 2011, at 12:44, T.R. 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.
>>
>> -- G.
>>
> 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?
>
> - D.R. -
>
|