Let me add one little story:
for our insurance math package, which we deploy on many different
platforms,
we kept for a very long time two target platforms, although they were no
more needed
by customers, simply because we made the experience that there were
sometimes
logical errors in our software which only showed up on those platforms
(because these
platforms were very "sensible" to hidden logical errors). The two
platforms were:
OS/2
and Sun Solaris
I believe, on the OS/2 environment, the reason was that even little
errors with array
indexing lead to segmentation errors (which did not show up on Windows).
On Sun
Solaris, there were other kinds of errors, which had to do with the
alignment of shorts,
ints, and longs. While optional on other platforms, this was mandatory
on Solaris.
In the last few years, we added Intel-64 with Linux to our supported
platforms, which
added some new (64-bit) problems.
We are also constantly fighting with rounding problems - successfully
most of the time - ,
because we use the classical HEXADEC representation for floating point
on z/OS
(we have to communicate with PL/1 and - classical - ASSEMBLER).
Kind regards
Bernd
(still running two OS/2 development machines from 1997 and 1999)
Am 02.01.2012 10:55, schrieb Bernd Oppolzer:
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 Thomas David Rivers:
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