If you have a quick stream of consciousness reply, that would be great
since I can get back to you if I need more detail.
Please e-mail your response; if there is enough interest I'll post a summary.
thanks in advance!
_Blaine
---
Blaine Price (416) 978-6619, fax: 978-4765 d...@dgp.utoronto.{ca,bitnet}
Dynamic Graphics Project d...@dgp.toronto.edu
University of Toronto, Canada M5S 1A4 ...!uunet!dgp.toronto.edu!doc
Nine years ago (1983), my own software company was implementing a
multi-user server under MVS for a mainframe 4GL product called
RAMIS II (which at the time, only supported single user database
access). We used MVS cross-memory services to transmit data requests
from one process to another, but we chose to use the MVS ENQ/DEQ
facility to signal from one process to the other when an action had
completed. The system was up and running, and it worked reasonably
well, but at several installations, particularly with large numbers
of users, occasionally the server would lock up and stop accepting
new requests. We tried to trace it, but having little experience
with concurrent processes and multi-tasking, and with a lack of good
debugging tools on MVS, we were pretty well lost.
(The 4GL company comes out with their own multi-user system, our
market dries up, my company goes out of business. Cut to 1991).
I am in a discussion with another senior scientist at my new employer
Locus, along with several of my staff talking about how we will handle
some Unix shared memory stuff in our new database access query
product which will require multiple back-end database processes to
handle multiple queries along with an interface to Motif. The
other senior scientist, at the end of the discussion, points out
just for the record, to be sure to lock resource A PRIOR to releasing
the lock on resource B to make sure there is no window, no matter
how infintesimal, in which a resource conflict could occur (there is
no possibility of a deadlock). Memories stir, visions swim into
my mind and the original code of my 1983 product comes streaming
back into my head. I see the Assembler code clearly in my mind:
DEQ X
ENQ Y
Ooops!!!! I go back and look at the code, and sure enough, the problem
is as clear as day. Only it is several thousand days too late... :-)
Jon Rosen
This happened in my first year of University. We were required to write
a Fractal program (Koch's Snowflake) for the MacIntosh, using some form
of Pascal. The program had to (1) Draw the image on the screen, and
(2) output the corner points to a data file.
Anyways, I was used to Pascal on the MicroVax running Unix. Learning
the ins and outs of a different compiler, while also trying to figure
out the mathematics involved with fractals was a lot of fun :-)
I had gotten the Mac to draw the image on the screen (eventually), but
I was having trouble outputting the points to the data file. I looked
all through my code to try to find the problem... The procedures
to open the file, to output the points, everything seemed to be OK.
I asked the prof, the TA, anyone who might know Pascal, and nobody
could find anything wrong with my procedures. It didn't even seem
like it was calling the file open procedure.
Finally, one of my friends asked... "Where do you CALL the procedure
from?"
Oops, case solved. I had written the procedures, but I never actually
called them. (And the Mac Pascal compiler didn't give a warning, like
the Unix Pascal would have.) The program worked fine after that.
------------------------------------------------------------------------------
\ \ |Allan Sullivan (al...@cs.ualberta.ca)
\ \ |Department of Computing Science,
\ \_______ |University of Alberta, Edmonton, Alberta, Canada.
\ ### \ _ |---------------------------------------------------
\___###___\ (_) |My opinions are mine and mine alone.
------------------------------------------------------------------------------
"It is amazing how much can be accomplished if no one cares who gets the
credit..." - U. of A. Golden Bears Hockey Motto (C. Drake)
------------------------------------------------------------------------------
After much headscratching I found something similar to this...
CALL TEST (I, 5)
.
.
.
SUBROUTINE TEST (I, J)
.
.
J=3
.
.
FORTRAN passes things by address, and since you can't take the address
of a constant the compiler was putting the 5 into a memory location
and passing its address. The 5 was getting turned into a 3 by the
subroutine.
Unfortunately the compiler used that same location every time a 5 was
used in the code, so after executing my routine all the 5s in the rest
of the program became 3s...
Steve
>After much headscratching I found something similar to this...
>CALL TEST (I, 5)
>.
>SUBROUTINE TEST (I, J)
>.
>J=3
>.
>FORTRAN passes things by address, and since you can't take the address
>of a constant the compiler was putting the 5 into a memory location
>and passing its address. The 5 was getting turned into a 3 by the
>subroutine.
>Unfortunately the compiler used that same location every time a 5 was
>used in the code, so after executing my routine all the 5s in the rest
>of the program became 3s...
>Steve
Yep. Standard FORTRAN behaviour. Thats how almost every FORTRAN compiler
will do it! (I didn't run into this one by accident)
Roger
--
If the opposite of "pro" is "con", what is the opposite of "progress"?
(stolen from kadokev@iitvax ==? tech...@iitmax.iit.edu)
EMail: wo...@duteca.et.tudelft.nl ** Tel +31-15-783644 or +31-15-142371
Maybe I'm lucky, I've never found any other FORTRAN compiler which
does it that way!
Steve
You are lucky. The FORTRAN compilers for the DecSystem-10, running TOPS-10,
all exhibited this behaviour---as demonstrated by a bug I found hellish to
resolve.
-- Michael Jones m...@sgi.com 415.335.1455 M/S 7U-550
Silicon Graphics, Advanced Systems Division
2011 N. Shoreline Blvd., Mtn. View, CA 94039-7311
Steve
I had a friend in school who got p-o'ed that he wasn't allowed to skip
the intro programming (in FORTRAN, in those days) requirement even
though he was thoroughly fluent in PL/1. So he took it out on the
TA's. One of the assignments was to write a bubble sort. His
solution took advantage of the not-so-constant constants described
above (he was using the G compiler on an IBM 360/91, which exhibited
this same behavior). He had constant loop indices and such, but with
a few subroutines that would alter the constants as required to make
the thing actually work.
On another assignment he made use of a weird feature of the WATFIV
(from University of Waterloo) instructional FORTRAN compiler. This
compiler recognized a special multi-punch combination (yes, I said
"punch" - as in punched cards!), which they called "Zigamorph", as
introducing a comment that would run to the end of the card. In the
source listings, zigamorph printed as a blank. So you could write
statements like:
x = y + 2@* sin(z)
(where '@' denotes the zigamorph). The compiler would see "x = y +
2", but the poor TA saw "x = y + 2 * sin(z)". The result was that the
TA was absolutely certain the program could not be correct, yet it
would run perfectly on all test cases. Nearly drove the guy crazy.
--
Andy Lowry, lo...@watson.ibm.com, (914) 784-7925
IBM Research, P.O. Box 704, Yorktown Heights, NY 10598
I was in charge of installing VRTX 86 and FMX (real time operating
system+ file system) on new hardware. We had everything running fine,
but the database access was hideously slow because of using buffered
I/O for database file access. So I changed the program to use direct
I/O, and it stopped working.
Well, I knew that the problem had something to do with buffering, so I
wrote a test program. Test program works perfectly. Scratching of
heads ensued.
Then, in combination with unrelated stuff getting loaded, I discovered
that the problem was address sensitive. Seems that if the program's
data buffers get placed about 128K, the program fails, below that it
works. THIS is the clue. This was on an 80188, which has a split
addressing scheme so as to support lashing on ROM without intervening
circuitry. Turns out (on appealing to schematics ;-() that the DMA
read into 'middle' memory wasn't working properly. When we were using
buffered I/O, all writes and reads were copied through OS buffers in
low memory, so we never saw the DMA problem.
Of course, the EE guys thought I was nuts; I had to write really ugly
macros with the I^2ICE in order to prove it to them.
Reading this, it sounds a little dry, but it was definitely one of
those 'am I crazy, or is it the machine?' situations. Oh, and the
protypes sometimes wouldn't boot until you gave them a solid whack
against the bench!
--
Kent Williams | "Do you see your cerebellum as a lightbulb or a cog? I
will...@cs.uiowa.edu | saw mine as gristle so I fed it to the dog. But it
Quote: Bevis Frond | taste so bad, that she left it in the bowl ..."
A friend of mine (name withheld to protect the innocent), who was used
to C but needed to write a program in Pascal, told of a particularly
disturbing debugging incident. It seems that there was a loop in the
program that just wasn't getting executed! When you stepped through
with the debugger, it would just step right past the loop, with no
apparent reason for its failure to execute.
It turns out that he had used braces { } instead of BEGIN/END to
delimit the body of the loop. Braces, of course, are comment markers
in Pascal.
Carl Witty
cwi...@ai.mit.edu
Jon Rosen
Well, I examined the compiler output, and soon noticed that the 0C4 was in
a different subroutine from the one with the WRITE statement. The traceback
was all in machine addresses, but fortunately the compiler prints a table
giving addresses for labels in the program. I was able to estimate which
Fortran statement was executing at the time of the 0C4. It was a CONTINUE
statement at the bottom of a DO loop. It looked like this:
IF ( some condition ) GOTO 100
.
.
DO 100 another condition
.
.
100 CONTINUE
101 something else
Now the Fortran manuals warn you never to branch into the middle of a DO
loop, and they consider the terminating CONTINUE as a part of the loop.
This is because you are bypassing the loop initialization. I happened to
know that a BXLE instruction lives where the CONTINUE is.
So, I told him to change the GOTO 100 to GOTO 101 and the program would
work. He did, and it did. He was amazed. I was pleased.
--
-Gary Mills- -Networking Group- -U of M Computer Services-
>>>> CALL TEST (I, 5)
>>>> .
>>>> SUBROUTINE TEST (I, J)
>>>> J=3
This was indeed conventional Fortran behavior, though the 1966 standard
neither required nor prohibited it and I'm not sure about later standards.
This is why conventional Fortran PROGRAMMING would have used this technique:
CALL TEST (I, (5))
In PL/I, there would not have been any problem with the 5.
CALL TEST (I, 5);
would be just fine. But if you wanted to protect the value of I, you would
CALL TEST ((I), 5);
C (and its derivative, C+=0.01 :-) are the only languages I have used where
parentheses don't change an lvalue into an rvalue. Of course, C NEEDS the
feature that keeps lvalues as lvalues, because it is good practice to wrap
macro arguments in parentheses in defining the replacement string of a macro.
It doesn't matter to function arguments because they're always call-by-value.
Now that C+=0.01 has invented references (the same thing that C lovers used
to love to criticize about Pascal, Algol, Fortran, etc.), AND an extra layer
of parentheses don't convert a function argument into an rvalue, it should
be pretty hard to avoid this kind of problem.
--
Norman Diamond dia...@jit081.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.
"Yeah -- bad wiring. That was probably it. Very bad."
I prefer to think that it shows the age of the computer I was working with :-)
Steve
>>After much headscratching I found something similar to this...
>>CALL TEST (I, 5)
>>.
>>SUBROUTINE TEST (I, J)
>>.
>>J=3
Its not just Fortran that suffers this. I wasted half a day on a similar
problem in Turbo Pascal.
I was attempting to read the mouse position from the driver. They way
this is done is to load magic numbers into various registers, and call a
magic interrupt. TP has a call to do this (can't remember the name) that
takes as parameters a register list, and maybe a interrupt number.
I had put the magic registers in as structured constants. I called the
interrupt. It worked. I called it again. It didn't.
What I didn't know was that the register list was a *var* parameter.
Silly me.
John West
--
gu...@uniwa.uwa.edu.au For the humour impaired: insert a :-) every 3 words
First compiler that comes to hand, f77 on Sun4. Don't know what level.
Yes, I know it has the reputation of not being the smartest Fortran
implementation that ever was created. But it's in common use.
--------------------------------------------------------------------------
sun13>cat t.f
print *,' before ',1
call sub(1)
print *,' after ',1
end
subroutine sub(n)
n=2
end
sun13>f77 t.f
t.f:
MAIN:
sub:
sun13>a.out
before 1
after bef 1 543254132
sun13>f77 -O t.f
t.f:
MAIN:
sub:
sun13>a.out
before 1
after bef 1 543254132
sun13>
--------------------------------------------------------------------------
> ...... Under any recognized
> FORTRAN standard, the above behavior is a bug, pure and simple.
NO Fortran standard EVER specified what should happen in case of a
programming bug, e.g. when the stupid user writes into a constant
parameter. The standard only specifies what happens in case of a *correct*
program.
In the days of my youth, when *I* learned to program Fortran, ALL compilers
behaved that way. They were written by assembly-language programmers who
didn't see any need to protect the users from their errors. After all, they
(the compiler implementers) knew to avoid the problem (which is an obvious
one when writing in assembly), so why couldn't the stupid application
programmers learn to do the same ?
Another hardy perennial is :
sun13>cat t.f
call sub(i)
end
subroutine sub(i,j)
print *,'j=',j
end
sun13>a.out
j= -1646018656
sun13>
Also quite hard to debug. Usually in the form
call sub(p1,p2,p3,p4,p5,p6,p7,p8,p9)
....
subroutine sub(p1,p2,p4,p5,p6,p7,p8,p9)
(By the way, TMC's CMF, also running on Sun4, gives a segmentation fault
on the first error program. Some compilers are smarter than others.)
------------------------------------------------------------------------------
Daan Sandee san...@sun16.scri.fsu.edu
Thinking Machines Corporation
Supercomputer Computations Research Institute, B-186
Florida State University, Tallahassee, FL 32306-4052 (904) 644-4490
From the last time this came around on comp.lang.fortran, I understand
that a program that passes an expression (or constant) as an argument
to a subroutine that modifies it is not standard-conforming, so the
compiler is within its rights to do either of these things (or
anything else). Compilers that behave as Rosen describes (most of
them since Fortran II, in my experience) are being helpful, but
relying on this behavior is *not* portable.
(Sorry about the language-specific post...)
--
Matthew Saltzman
Clemson University Math Sciences
m...@clemson.edu
In article <pfvo9...@grapevine.EBay.Sun.COM>, smck...@sunicnc.France.Sun.COM (Steve McKinty - Sun ICNC) writes:
|> In article <1992Mar09....@donau.et.tudelft.nl>, wo...@dutecai.et.tudelft.nl (Rogier Wolff) writes:
|> > smck...@sunicnc.France.Sun.COM (Steve McKinty - Sun ICNC) writes:
|>
|> >
|> > >Unfortunately the compiler used that same location every time a 5 was
|> > >used in the code, so after executing my routine all the 5s in the rest
|> > >of the program became 3s...
|> >
|> > >Steve
|> >
|> > Yep. Standard FORTRAN behaviour. Thats how almost every FORTRAN compiler
|> > will do it! (I didn't run into this one by accident)
|>
|> Maybe I'm lucky, I've never found any other FORTRAN compiler which
|> does it that way!
|>
|> Steve
You are lucky. The FORTRAN compilers for the DecSystem-10, running TOPS-10,
all exhibited this behaviour---as demonstrated by a bug I found hellish to
resolve.
I guess it'll fail on just about any machine without memory protection.
VAX/VMS does have memory protection, and puts constants as well as code
on readonly pages, so the program bombs trying to write to a readonly
address, instead of -quietly- rewriting constants.
We've ported code from CDC NOS to VMS and found _lots_ of places where
this was done, and it just happened to work ok on the Cybers. I prefer
VMS's behavior, since I don't like a computer accepting my buggy code.
(So I use C, with full ANSI prototyping.)
--
J Lee Jaap <jaa...@tab00.larc.nasa.gov> {+1 804/864, or FTS 928}-2148
employed by, not speaking for, AS&M Inc, at NASA LaRC, Hampton VA 23665-5225
>On another assignment he made use of a weird feature of the WATFIV
>(from University of Waterloo) instructional FORTRAN compiler. This
>compiler recognized a special multi-punch combination (yes, I said
>"punch" - as in punched cards!), which they called "Zigamorph", as
>introducing a comment that would run to the end of the card. In the
>source listings, zigamorph printed as a blank. So you could write
>statements like:
> x = y + 2@* sin(z)
>(where '@' denotes the zigamorph). The compiler would see "x = y +
>2", but the poor TA saw "x = y + 2 * sin(z)". The result was that the
>TA was absolutely certain the program could not be correct, yet it
>would run perfectly on all test cases. Nearly drove the guy crazy.
That wasn't at all unique to WATFIV; the IBM compiler (IBFTC) had the
same behavior. When it was time to begin to scan a new FORTRAN source
statement, the input routines would pick up the next card, then read
successive cards until one was found which did not have column 6 punched.
(This stopper card would be saved for the next cycle.) Column 7-72 of
all the continuation cards would be concatinated together, and at the end
of the last card the scan routine would drop a word of all 1's as a
fence.
Since the card was scanned one character at a time, the user could punch
an octal 77 into the card at any point; that would cause the scanner
to believe that it had run into the fence and stop the input parse
at that point.
Since back in Ye Goode Olde Dayes the standard high-speed printer might
be able to print 48 of the 64 possible character patterns, the octal 77
would appear on the printed listing as a blank.
Joe Morris
Trivia question: name the five phases of the 7040 IBFTC compiler. Why
were there *six* source files? Which one or more of these phases
actually wrote the binary deck image?
PS: the last question is a trick question. That's a hint.
More trivia: what statements in FORTRAN programs compiled with WATFOR/WATFIV
on the 7040 were executable even though the FORTRAN language specification
identifies them as nonexecutable? Repeat the question for the 7040 IBFTC
FORTRAN compiler.
If by "standard" you mean the formal ANSI and ISO standards, this is
technically incorrect. The program fragment originally presented was a
non-standard-conforming *program* due to the assignment to a constant. And all
of the Fortran standards say that when a standard-conforming *processor*
encounters a non-standard-conforming *program*, it can execute that entire
program any way it damn well pleases. A single non-conforming construct in the
program releases the processor from any responsibility for attempting to
conform to the standard in any part of the program, yet it may still execute
the program as an extension and call itself a standard-conforming processor.
And therefore the behavior described is perfectly standard-conforming.
Now, actually, I agree with you: it's a bug. But it's a bug *in* the standard,
not *under* the standard. Unfortunately, X3J3 doesn't agree with me.
Edward Reid (8-}>
eel: e...@titipu.meta.com or nosc.mil!titipu.meta.com!ed
snail: PO Box 378/Greensboro FL 32330
That's certainly not the nastiest debugging stint I've put in. But don't we all
remember the interesting ones more than the nasty ones? I'm sure the nastiest
cases for me have been problems showing up on a customer's system, hundreds or
thousands of miles away, no access to their system, can't reproduce the problem
locally. Debugging by asking a customer to run tests while I read the code is
not fun.
Yes, the Fortran compiler was written in assembly, and the designers did
know not to call routines that way, but as pointed out, the users ought to
know better, etc.
The point wasted in the discussion is that there is no usefullness to doing
any specific "solution" to just how invalid usage behaves. Certain writers
of C code wouldn't want compiler "intervention" for their usage merely
because it is out of the ordinary, so why is this any different? The results
of misuse may vary, and in any case are undefined.
Moreover, anyone wanting the usage more "protected" is inviting inefficiency
on all programs, which is simply undesirable. Fortran is a language where
a long time ago it was decided that a goal was fast execution of functional
code, not someones notion of what-ifs on non-productive programs.
Besides, people have had fun noticing what quirks do what while doing some
marginal things on purpose for years :-). There used to be magazine columns
devoted to exploiting quirks on certain implementations.
cjl
>[debugging faulty bit in system clock]
>That's certainly not the nastiest debugging stint I've put in. But don't we all
>remember the interesting ones more than the nasty ones? I'm sure the nastiest
>cases for me have been problems showing up on a customer's system, hundreds or
>thousands of miles away, no access to their system, can't reproduce the problem
>locally. Debugging by asking a customer to run tests while I read the code is
>not fun.
When I was writing business software in Business BASIC on DG minis in
the early 80's, we would frequently get calls from a terminal operator
on a customer's site, with some sort of runtime error (BusiBASIC is
interpreted, so it could be _anything_). There was no idea at the
company of keeping accessible copies of all the customers' software
(it would have been too much code---some of these systems were over a
million lines of source---so we had it all on tape somewhere or other,
except for on-site modifications which somehow hadn't made it back to
base), so we'd have to diagnose entirely from printouts, and dictate
fixes to someone at the other end who didn't even know what a `slash'
was, and would frequently put O for 0 or o. (side-note: we made sure
we had at least one of all DGs terminals in our own offices, so we
could ask them what they were using and then go sit at the equivalent
terminal to say things like `No, the key to the right of the P').
I remember one particular Friday when a customer rang me at about
4:40pm. All the employees at his site were due to go home in 20
minutes, with pay cheques, and the payroll program had died before
printing a damn thing. Our copy of their sources was out on the road
with one of our analysts, and I didn't even have a listing. Somehow I
managed to reconstruct their system, dictating maybe 20 lines of code
by sheer seat-of-the-pants programming, launching him back in with a
`GOTO' that popped him right back into his payroll control screen.
At the time, I could have been earning more money working at
McDonalds.
Nick Haines [names removed to protect the guilty, except
ni...@cs.cmu.edu McDonalds who don't deserve protection]
To put it a bit stronger,
(a) The Fortran 77 standard includes the CONTINUE statement in the range
of a DO loop, explicitly,
(b) The Fortran 77 standard prohibits jumping into the range of a DO loop
So a user had
do 100 i=...
if (x(i).lt.0) goto 100
do 100 j=....
...
100 continue
Program ran as he wanted on platform A but compiler returned an error on
platform B. I had a lot of trouble explaining to him that (a) his program
was non-standard-compliant and (b) Fortran implementations could do whatever
they liked with non-compliant programs.
So he went off hating compiler B but was he right ? Do we really want to
have compilers that accept sloppy programming and dream up some code which
(in this case) did what he wanted ? (Presumably, he meant to cycle the
outer loop.)
The background for the position taken by the standard (that the compiler
can do what it likes for nonstandard Fortran) is the fact that most compilers
have nonstandard extensions and the standard explicitly did not want to
disallow extensions. To guard against problems as the above, it would have
to proscribe them explicitly (as it prohibits jumping into a DO range) ;
a catchall "don't accept nonstandard code" won't work.
(This is getting away from the subject of debugging horrors, sorry.)
The information missing is: The error occurred only if the file
decriptor masks were all zero, i.e.,
FD_ZERO (&read_set);
FD_ZERO (&write_set);
FD_ZERO (&except_set);
select (FD_SETSIZE, &read_set, &write_set, &except_set, NULL);
I have checked this on our machines just now and the bug is no longer
there.
--
+------- No .sig? OH, COME ON! --------+-"The derivative snuggles close to-+
| email: neu...@informatik.uni-kl.de | the function---whatever to snuggle |
| snail mail: Stephan Neuhaus/Hilgard- | means; I'm too old for that" |
| ring 32/6750 Kaiserslautern/Germany | -- Math Prof |
One bug that cost me one week to find:
Situation: A SUN UNIX workstation, running some version of SUNOS (most
probably 4.3 or 4.4), g++ compiler 1.40, gdb debugger (version unknown).
Project: Programming a replacement for Xt in C++ with nifty direct
manipulation features. (If that's greek to you, don't worry, it's not
important.)
The code consists, among other things, of a kernel that reads events
from network connections and dispatches them to objects. There is also
the possibility of installing a timer. Fortunately for us, SUNOS
provides the (originally 4BSD) system call select(2). What select does
is to wait for a) something to happen on a set of file descriptors, or
b) the expiry of a timeout, whichever comes first.
I had programmed something like this before, using signals, so I used
the same approach. I installed a signal handler, provided for the timer
to go off at some time, and called select() with no timeout, i.e., told
the operating system to wait indefinitely for something to happen on a
network connection. What I had in mind was, ``the timer signal will
abort the select() call, so I'll return whenever something arrives on a
network connection or when the timer expires, whichever comes first''.
In the other program, it had worked just fine. Here, it didn't.
OK, I entered the debugger. The program worked! I was frustrated. I
said, ``OK, let's try printf-debugging.'' After I inserted some
print-statements, the program worked---sometimes, sometimes not,
seemingly depending on where and when I printed something. I screamed
and raged. Then I removed the print-statements and tried to send the
program a timer signal from the outside, with the UNIX command kill.
The signal got through and the program proceeded, despite the fact that
the signal, when requested from the same process, did not get through.
OK. I tried to trace system calls, using strace(1). The program
worked! I tried trace(1). The program worked. I tried to attach to the
process with trace(1) or the debugger after it hung. After I attached,
the program became unstuck and worked just fine.
In other words, as soon as I was trying to find out what the heck was
happening, the bug disappeared. The remedy was, of course, to include
the timeout in the select(2) call, not as a signal. I still don't know
exactly what went wrong, but I've decided that it a) has got something
to do with the way UNIX process proirities and signals work together,
and b) is a bug in SUNOS. (My first conjecture was confirmed when I
read in the 4.3BSD book that sometimes processes blocked in a system
call will not be awakened by a signal.)
That was pretty frustrating, I can tell you. After I included the
timeout in the select(2) call, the code ran OK, and still runs without
ever an error.
Scary...
<some code where the variable flag is set to the value TRUE>
if (flag = true) then
<other code>
The problem was that the if test was not being executed even though
flag was true. I proceeded to step through this code a few times
mostly to prove to myself that this was really happening. I was
about to give up, when I saw that the user had declared two
Boolean variables "true" and "false". Think Pascal on the Macintosh
kindly initializes all globals to 0 so these two variables had
the value FALSE to the computer since "true" and "false" are
not reserved words.
Peter
We were simply the victims of our own bad code in this case. It
is problems like the above and the FORTRAN glitch that started this thread
which prompted the Government to build Ada. Unfortunately Ada has gone
so far to the strict type checking extreme that it is very hard or cumbersome
to do many of the things that are easy to do in C and with all the run-time
type checking will require triple the execution time. I personnally think
the compromise position is a combination of language support like the
function prototypes in ANSI C and better tools like Saber/Codecenter and
Purify.
By the way we obtained an evaluation copy of Purify and decided to
buy it after it located several serious memory bugs within an hour of us
installing it. This software could easily rank right up with sliced bread
and canned beer, and is certainly one of the best software products we will
see delivered this year.
--
David W. Boyd UUCP: uunet!sparky!dwb
Sterling Software IMD INTERNET: d...@IMD.Sterling.COM
1404 Ft. Crook Rd. South Phone: (402) 291-8300
Bellevue, NE. 68005-2969 FAX: (402) 291-4362
(2) In the MESA language, on a Xerox DLion (Star Environment),
remotely debugged: Every so often some database code would raise an
exception, it would be passed maybe 5 outer scopes until it was
caught, then the catching software would run for a while and raise a
second exception, perhaps using the cryptic "RETRY" feature in the
language, and then the machine would crash into the world-swap
debugger. Many people saw the crash over a period of 2 years, using
the symbolic debugger. The set of scopes and exception and stack
trace was so cryptic and complicated, they would look at it for half
and hour and then quit, mystified about the course of execution and
the cause of the bug. One day I found the bug had happened to my
machine. I got so pissed off I simulated the code on paper by hand
for several hours. It turns out there was a compiler bug in the code
generated for handling exceptions. The machine language was a company
secret; I had no way of inspecting the compiled code, and yet, I
figured it out. I called upon Dick Sweet (compiler writer) to look at
the bug, and he agreed it was a bug in the compiler.
(3) Best bug I know of: The cyber 175 here on campus developed an
error in its floating point unit, causing small inaccuracies in the
results of certain arithmetic computations. This error continued for
several months, whereupon, it was discovered by someone very clever.
Several hundred hours of astronomical calculations had to be re-run
because the output was suspect.
Don Gillies - gil...@cs.uiuc.edu - University of Illinois at Urbana-Champaign
--
I have here a couple of things to mention before getting to my fun bug/feature.
re: FORTRAN and calling by reference
I heard that on some some old systems, one could actually subvert the
system's master EBCDIC table by redefining constants. Wouldn't that be nice?
Try figuring out that the bug in your program is in someone ELSE's program.
(This may, or may not qualify as an "urban legend" type of thing. I have not
tried to verify this by reproducing the result)
Since people have been mentioning BASIC, the quintessential Applesoft BASIC
bug has not yet been mentioned. I ran into this fairly rarely in my own
code, but I've nailed it in other people's code.
The program simply crashes, either on the line in question, or somewhere else,
or just doesn't do what it's supposed to do. The problem was most prominent
in high-school computer literacy courses, where the teachers thoughtfully
told the students to give the variables useful, and descriptive names.
Well, Applesoft ignores everything after the first two letters, and many
people unwittingly use the same first two letters in several variable names
without realizing this limitation. When they list it, everything is fine.
It just doesn't work right. This actually isn't the thing I was thinking
of, but it's a good one too.
The problem I was thinking of was this: use of reserved words in variable
names.
i.e.
100 IF APPLES = ORANGES THEN GOTO 200
The OR is a reserved word, and gets tokenized. When the interpreter encounters
this line, the likely result is a syntax error. If the column width is set
high enough, the computer will insert a space after the OR, and the
reserved word sticks out like a sore thumb. However, novice users still don't
get it, and advanced users always set the column width to 33 characters so
that the computer will NOT insertspaces.
Diabolical.
On to my C entertainment.
While writing a compiler in Borland C++, I had some real fun. Aside from
the normal Borland fun (i.e. berserk mouse drivers, compile crashes, etc.)
after adding 10 lines of simple code, the program changed from a well-
behaved one, into one that hangs the computer when you run it. Excellent.
The code I added only initialized some data lists that I was already using.
The code was IMMEDIATELY at the begining of the main() procedure.
It merely initialized the lists, and added data that was common to all
source files that would be encountered. Nothing big, nothing critical.
Very simple.
And that wasn't even where the program died.
Running in the degugger:
1- when single stepping, it runs fine.
2- turn it loose, and it crashes horribly.
Great.
I decided that I must be at fault, and spent 24 hours stepping through code,
and inspecting everything in a magnifying glass.
[note: this process was much more grueling than it appears, but you don't care,
so I'll spare you further details]
At some point, my mind received a message from an alternate dimension. It
directed me to look more carefully at the Borland manual on the IDE
(programming platform with crippled debugger, compiler and editor)
options. Under the optimization section, it detailed the
"Register Variables" option. It said that this should normally be left on
automatic. In fine print, somewhere around there (+/- a page) it said
that the compiler could sometimes be confused by indirect manipulation of
data (via pointers). Gee, who would think to use pointers in C?
Silly me. Well, this was the problem. I set it to "off" and the damn thing
worked fine.
This option should be set off by default, and the manual should
say "do not use this option, as our compiler is not nearly as smart as we
would like you to believe. When you are done, turn it on, and see if the
program still works."
I've had more fun with Borland compilers, but enough for now.
Ask me about the UNIX C program I wrote that compiled flawlessly, but
generated core dumps before executing even the FIRST LINE of my code.
Computers suck.
Andrew Gilchrist
The man who lost his .sig file in a bizarre gardening accident.
[FORTRAN allows writing into constants]
>
>Maybe I'm lucky, I've never found any other FORTRAN compiler which
>does it that way!
>
>Steve
Many FORTRAN compilers do this, old and new. He was indeed lucky that he
didn't try the software that his own company sells. f77 under SunOS 4.1
shows the same behaviour.
I also tried this with the FORTRAN II compiler on our PDP-8 under OS/8.
After I found out that you have to compile each FUNCTION or SUBROUTINE
separately, I got the same behaviour.
While I'm at it, I recently noticed that we don't have ODT (the PDP-8
debugger) for OS/8. It seems that there was a special OS/8 version of
ODT to support swapping and other advanced features. Does anyone out
there have a copy of ODT for OS/8? (Charles Lasner, maybe?)
--
Hans-Georg Zipperer Universit"at Stuttgart, Institut f"ur Informatik
Tel. (0711) 7816-405 e-mail: zipp...@ifi.informatik.uni-stuttgart.dbp.de
> You are lucky. The FORTRAN compilers for the DecSystem-10, running TOPS-10,
> all exhibited this behaviour---as demonstrated by a bug I found hellish to
> resolve.
>I guess it'll fail on just about any machine without memory protection.
>VAX/VMS does have memory protection, and puts constants as well as code
>on readonly pages, so the program bombs trying to write to a readonly
>address, instead of -quietly- rewriting constants.
TOPS-10 had memory protection, but only one segment, the "high" segment which
was intended for code. Only the high segment could be shared so DEC put
the runtime system into the high segment to be shared by all Fortran users.
The program private code went into the unshared data segment.
--
Anthony Shipman "You've got to be taught before it's too late,
C. P. Software Before you are six or seven or eight,
19 Cato St., East Hawthorn, To hate all the people your relatives hate,
Melbourne, Australia, 3121 You've got to be carefully taught." R&H
I moved a function from one place to another in a file of C code. I
compiled the file, and the compiler bombed with some internal error. I
figured I had introduced a typo, so I checked what I did. Funny. No
detectable problems in the source code.
Eventually I checked the source code for the C preprocessor and figured
out what was going on. The C preprocessor had a bizarre
double-buffering scheme that produced results that were dependent on the
position of #defines in the source file.
It just so happened that by moving a function, I had placed a large
parameterized #define just right so that the C preprocessor could no
longer scan it.
Grrr.
Ah yes, things that users do to get themselves into trouble.
This is Fortran again. User came to me with
do i=1,100
call sub
100 continue
Problem was, it appeared 'sub' was called a varying number of times,
(the code sequence above was executed several times). Never exactly 100.
After long head-scratching, saw optimizer had put out a message
"can't optimize this loop, control variable is not local."
WHAT? Turned out, 'i' was in COMMON. And yes, 'sub' went and modified it.
Told user, good idea to have control variables 'i','j','k', but NOT a good
idea to have them in common. I don't think the user appreciated the
enormity of the error, though.
One day a new operator calls the head accountant to show her the message
on the screen..."Shut 'er down, Clancy, she's a pumping mud!"
The oil-patch slang was a debugging flag left in the code and displayed
when a series of operator errors led to writing to a non-existant device.
--
Robert H. Geeslin, Ed.D. | Department
Gee...@VMS.OCOM.OKSTATE.EDU | of
doing EDucational Programming for 20 years | P. and B.S.
Given this rather astounding bug report it took me only a few minutes
to check the microfiche for the hyperbolic arc cosine routine and
discover that it saved and used registers 14 through 7 but restored
only 14 through 6, thus destroying register 7. And of course the only
time the generated FORTRAN code got around to using register 7 was for
the result IFF it was in a different labelled COMMON block etc.
Don't you just LOVE users like that?!?!
Wayne Hathaway domain: wa...@Ultra.COM
Ultra Network Technologies uucp: ...!ames!ultra!wayne
101 Daggett Drive phone: 408-922-0100 x132
San Jose, CA 95134 direct: Hey, you!
>I'm looking for some serious anecdotes about particularly nasty
>or bizzare debugging experiences that you have come across in large
>pieces of software (language doesn't matter). I'd like to know what
>the symptoms were, and what you eventually used to home in on the
>bug (e.g. some systematic method, a particular debugging tool, did it
>come to you in your sleep, etc.).
My worst debugging experience occurred when I was working (as a co-op)
on a large CAD program for layout verification (written in a bizarre
combination of languages but mostly PL/I) for a company that shall
remain nameless...
The program would operate completely normally sometimes and at other
times crash badly. The core dumps were very little help and seemed to
indicate that the program was crashing in different routines on
different runs. I was even more confused because I was using the exact
same input files every time.
Being a lowly EE co-op student, I enlisted the help of one the local
software gurus to help me find the problem. We eventually found that
somewhere along the way a pointer to a call back routine had
been filled with a float pointer. Sometimes, when the call back had been
invoked it would resolve to a valid address and at other times it
wouldn't, Thus, where the program would crash was dependent on where it was
loaded into memory at the time because the pointer to float changed with
every run.
I remember discussing with the guru how amazing it was that the program
had ever appeared to work. (This code (with bug) had been in place for
over a year before I had even started work on the project and had been
released to users.)
--
/**************************************************************************/
/* Kent Dalton * EMail: Kent....@FtCollinsCO.NCR.COM */
/* NCR Microelectronics * */
/* 2001 Danfield Ct. MS470A * */
/* Fort Collins, Colorado 80525 * (303) 223-5100 X-319 */
/**************************************************************************/
This PIZZA symbolizes my COMPLETE EMOTIONAL RECOVERY!!
Years ago, I needed to invert the sequence of lines in a file and do a
little of additional processing so I slapped together a quick 'lex'
program to do what I wanted. It worked perfectly if the output was
going to the screen:
reverse < data
but died horribly if the output was redirected:
reverse < data > file
I remembered that one of the reasons I went to 'lex' was that piping
'tail -r' into 'sed' did not quite work due to some buffer overflow,
and quickly discovered that 'lex' uses a default buffer only 200
characters long. Since some of my tokens were > 1000 characters, the
reason was obvious and the fix was easy. Curious as to why the buggy
program behaved so strangely, I run it under dbx and found that the
crash happened somewhere deep in exit(). Also, the actual output was
correct... This weirdness was passed on to a guru who determined
something to the effect that lex clobbered a link at the end of the
list of open file descriptors, changing it from NULL to something
random; for some weird reason this did not happen when the output was
going to the screen ...
KK
--
Kris Kozminski k...@mcnc.org
"The party was a masquerade; the guests were all wearing their faces."
I disagree. It's not a bug in the standard, it's a bug in the language design
like the ghastly precedence levels in C. The standard has no way to fix it. Once
you have call by reference and allow optimisations there's no other way to go.
--
-- Peter da Silva, Ferranti International Controls Corporation
-- Sugar Land, TX 77487-5012; +1 713 274 5180
-- "Have you hugged your wolf today?"
--
Bob Harper (r...@cs.cmu.ed)
Counter-example:
CALL SUB(5+5)
A = 10
PRINT A
END
SUBROUTINE SUB(X)
X = 9
RETURN
END
Does anyone really believe that this should print the value 9? Of
course not. 5+5 is evaluated and placed in a temporary. The fact
that the result is 10 should not result in the address of the constant
10 that is used elsewhere to be passed to SUB. I can actually see
where if this was allowed, an optimizing compiler might do exactly
that (by calculating 5+5 at compile time and converting it to the
constant 10, thereby screwing things up royally).
If the above code should work correctly, why should it be any different
for the code CALL SUB(10)? Again, my contention is that this is a
bug.
Jon Rosen
I want to attempt to redefine it a little: Most of the arguments from HLL
supporters are apparently using the line that HLL = C. Given incidents like
the debugging horrors recently described, and the problems of widespread use
of features that actually aren't standard, but merely "popular" if you happen
to code for a machine that supports that brand of "quirk", how can anyone here
claim that there is anything beyond superficial similarity to this alledged
language?
While Fortran's oldest "horn" about storing into a literal argument may indeed
be true, it is usually on the programmer's list of "features" not "bugs"
because Fortran just about always worked that way. Overall, there really
aren't as many problems with whose "brand" of Fortran you use, as long as
the compiler has the appropriate flavor of F66, F77, (F8X?) switches you
personally think are important. For the most part, they stick to the expected
value of the standard. Can anyone say the same for that moving target C?
Moreover, posters report that C people want their localized status quo to
remain that way; familiarity with quirks of a few implementations is more
important than standards I guess :-).
I nominate APL as the preferred HLL. Besides being compact, quirky, powerful
and ordered right-to-left, it hasn't been mis-implemented to death, so the
few versions that exist are a bit "closer" to each other. Besides, porting
couldn't take more than a few keystrokes to retype the whole program :-).
cjl (Once programmed in Aid)
>Here's a good one. As best I remember, it went something like this.
>[..]
>Eventually I checked the source code for the C preprocessor and figured
>out what was going on. The C preprocessor had a bizarre
>double-buffering scheme that produced results that were dependent on the
>position of #defines in the source file.
>It just so happened that by moving a function, I had placed a large
>parameterized #define just right so that the C preprocessor could no
>longer scan it.
>Grrr.
Grrr indeed. Preprocessors can be lots of fun. I once spent several hours
(well, at least 30 minutes) hunting the reason for a syntax error. As it
turned out, the error was on the very last line of an #include'd file, but
the errormessage showed up on the next line - in the #including file, which
the "intelligent" debugging environment promptly called up for my perusal.
Stephan Dahl
mara...@freja.diku.dk
That reminds me of a problem I had with a BASIC program. The program
was something like
<some code where flag is set to TRUE>
if flag then
<other code>
As in the above example the <other code> was never executed. Head
scratching. Print out flag, output "0". For comparison print out
FALSE, output "0". And at last, print out TRUE, output "0"!
That is TRUE = FALSE = 0 = logical FALSE (in this implementation).
A check in the manual showed that there was no such things as TRUE
and FALSE in this BASIC! So when I used TRUE and FALSE, new variables
were generated and initialized to 0.
To solve the problem I defined TRUE and FALSE in the beginning of
the program, but I never got the program finished :-)
(If TRUE and FALSE really isn't meant to be defined in BASIC then
pardon me because then there is no fun. But unless somebody explicitly
tells me "that's the way it is" I find it very difficult to believe
anybody would define a language which know of boolean operators but
does not know TRUE and FALSE)
And a similar story:
I a pascal program with a test like
<some code>
if flag then
<other code>
And (you guessed it): It wouldn't work, the <other code> was executed
when it wasn't supposed to. Just for the test I modified the program
to "if NOT flag then ...". The <other code> was still executed. That
is, both flag and NOT flag was TRUE.
I was ready to call it a compiler bug (it was still in my early days
of programming :-) ), when I discovered that I had forgot to initialize
"flag" :-(
The result was a boolean variable with a value which was neither TRUE
nor FALSE, so the boolean operations like NOT could not be suppose to
work. In fact the NOT was implemented as a binary NOT, and the test for
TRUE or FALSE in the if sentence was implemented as "FALSE = binary 0,
everything else must be TRUE".
Silly me.
+--------------------------------------------------------------------------+
| Lars J|dal | (put your favourite quotation here) |
| prot...@daimi.aau.dk | |
|--------------------------------------------------------------------------|
| Computer Science Department - Aarhus University - Aarhus - Denmark |
+--------------------------------------------------------------------------+
As an APL programmer who spends alot of time programming in Fortran
and C, I second the nomination! I've seen all sorts of strange Fortran
bugs/features/quirks (call them what you want - why can't I do
namelist input from a variable instead of a file?), and seen lots of
really ghastly examples here. I haven't noticed any horror stories
from APL, Lisp, Smalltalk, Prolog, or various others (did I leave out
your favorite?) as opposed to C, Fortran, and even Basic (I'd personally
group these and Pascal, Algol as subcategories of Fortran). I have to
admit that I'm surprised I haven't seen any on ADA. Is someone keeping
score? I'd say this is one way to distinguish HLL from LLL. The worst
problems I've had with APL are external things, like continuous CPU
limits on the 360 at Columbia (long ago) and the memory limitations of
IBM DOS. I've ported APL code from 360's to DEC20's to PC's (various
flavours) and while this can take some work it's still not in the same
class as redifining 0 for your program!
Another grouping is "generations" for example Fortran etc are often
categorized as 3rd generation, APL as 4th (or so).
--
Sam Sirlin
Jet Propulsion Laboratory s...@kalessin.jpl.nasa.gov
cjl (Once programmed in Aid)
Wow, AID -- Algebraic Interpretive Dialog -- by JOSS (sp?) ???
That's a blast from the past!
The only language I've ever known with, essentially, _floating_ statement
label numbers!
Did you run it on a PDP-10 by any chance?
--
James Craig Burley, Software Craftsperson bur...@gnu.ai.mit.edu
Member of the League for Programming Freedom (LPF)
cjl (Helping to propagate identical bugs into the 21st century)
Counter-example:
Your contention is wrong. The above code _cannot_ "work correctly" because
there is no definition of "correct", either in the standard or in the
minds of programmers at large. So the standard states that such a program
has "undefined behavior" as a result of executing "X = 9", meaning an
implementation (compiler) can do anything it wants. See 15.9.2 in the
ANSI FORTRAN 77 standard for some exact wording. And programmers are
of various minds; most want the behavior you assert is "correct", but
a large number define "correct" as "generates an exception when the
assignment is made" (produces faster code than your definition on many
popular machines), and a few even think it _should_ print "9" (though I
think they're crazy :-). I claim there is no single, useful, definition
of "correct" beyond Fortran's definition that the behavior is simply
undefined.
Further, not only does "anyone" (myself) believe that your sample program
_might_ print the value 9 on many systems (with the belief, as well, that
the "bug" is in your program), but many people believe that. And we are
all correct. We also are correct when we say that systems will do different
things with that program, of course.
There is no requirement that any evaluated expression be placed in a
temporary in the FORTRAN standard, by the way. That is an implementation
technique, often-used I admit, that many people (yourself included) have
implicitly read into the standard text.
For example, consider the following program:
PROGRAM X
CALL FOO(A,B)
CALL BAR(A*B+2)
A = A*B+2
CALL BLETCH(A)
END
There is nothing in the standard that requires the compiler to evaluate
the expression A*B+2 twice, or even that prevents it from rewriting the
program internally to
PROGRAM X
CALL FOO(A,B)
A = A*B+2
CALL BAR(A)
CALL BLETCH(A)
END
thus saving a temporary and perhaps some execution time (especially if
the code was in a loop). However, obviously if BAR modified its argument,
such a rewrite would result in _exposing the bug in the user's program to
some extent_, _not_ in producing "incorrect code".
Claiming that the ANSI FORTRAN 77 standard is wrong because it does not
require implementations to generate _slower_ code so _buggy_ programs either
behave "right" (based on an arbitrary definition of "right" -- "arguments are
passed by reference unless they aren't modifiable, in which case
they are passed by value") is a major waste of time, because:
1. The ANSI FORTRAN 77 standard is cast in stone.
2. It specifies FORTRAN, not some other language.
There are plenty of languages that have the behavior you want (and other
such "helpful" behavior), probably, but most of them are effectively
obsolete because people who wrote code in them didn't discover the code
had bugs until it was too late. For example, PL/I did implicit
conversion between strings and numbers (among other things) because it
"presumed" that if you said "mynumber = mystring;" you really meant "parse
the characters in mystring in decimal, store the result in mynumber"
rather than "oops I forgot the type of one of these variables" as was
the case 90% of the time. The result was that programs often appeared to
work for some data sets and would fail on others. I coded in PL/I for several
years, and though I liked the language, this artifical "hand-holding" was,
in my opinion, it's most severe weakness (compiler availability and
such issues aside), though of course experience has shown me that it had
other weaknesses of which I was only vaguely aware at the time.
FORTRAN has the problem that some implementations fail to properly detect
writing of a constant. But requiring _all_ implementations to silently
accept someone accidentally passing in a constant where the procedure
expected a modifiable argument and implementing it by just not rewriting
the "constant", along with other such "features", would have killed FORTRAN
long ago (perhaps mercifully, but that's another issue). This is true
for two reasons: one, it would have caused more bugs to go undetected for
longer periods of time, and two (less forgiveable in the FORTRAN community)
it would have slowed down the code generated by many implementations of
FORTRAN. Meanwhile, the real FORTRAN "problem" of not detecting rewriting
constants means it is no different from similar problems in other
similar languages (like C and Pascal).
> Well, again, I disagree that the standard has no way to fix it. My
> reading of the BNF is that arguments to subroutines or functions can
> be variables, subscripted variables, function or subroutine names,
> or expressions. I don't see that a constant or literal can be
> passed by itself. Therefore, if a single constant or literal is
> passed in, by definition it is an expression and MUST be evaluated.
> Since the result of an expression (even if it is no more than the
> original value) must be put in a temporary to be correct, the problem
> seems solved to me. That is why I believe it to be a compiler bug.
> ...
> Counter-example:
>
> CALL SUB(5+5)
> A = 10
> PRINT A
> END
> SUBROUTINE SUB(X)
> X = 9
> RETURN
> END
This code simply isn't valid FORTRAN. The FORTRAN 77 language standard states
on page 15-16:
"Actual arguments may be constants, symbolic names of constants, function
references, expressions involving operators, and expressions enclosed in
parentheses if and only if the associated dummy argument is a variable that
is not defined during execution of the referenced external procedure."
--
Steve Davies s...@peora.sdc.ccur.com {uiucuxc,masscomp,tarpit}!peora!srd
Concurrent Computer Corp/2492 Sand Lake Road/Orlando, Fl. 32809 (407)850-1040
About 10 years ago, I was writing some FORTRAN on a PDP-11/44 (with a
Floating Point Accelerator) running RSX-11M-PLUS V1.0 (F77 compiler).
Everything was going well until I started getting errors in a fairly
simple integer calculation. Being a good little programmer, I dug into
the program to find the bug.
After a thorough review of the code failed to turn up an algorithmic
error, I decided I must be doing something really stupid, and resorted
to single-stepping through the program with the debugger (ODT), checking
variables as I went. I got the correct result.
"All right," I thought, "I've changed something by compiling and linking
with the debugger." After spending a few hours looking for things that
might be changed by introducing debugger support (and not finding
anything significant), I ran the program again, single-stepping as I
went. Before too long, I ran out of patience, and hit the G key to let
the program run free. Well, what do you know, I got the calculation
error!
Over the next two days I tried everything I could think of to find that
bug. Finally, while stepping through the program for the umpteenth time,
something caught my eye: if I stepped through at one step per second,
the program worked just fine, but if I stepped through at two steps per
second, I got a calculation error! Of course no one believed be at
first, but eventually I convinced one of the hardware techs to swap the
FPA, and the problem went away.
The F77 compiler used the FPA to speed up certain integer calculations,
and it seems this Floating Point Accelerator had a timing problem which
generated bad results for this particular instruction sequence if they
were executed at full speed, but not if they came slower.
--
Reece R. Pollack
Senior Software Engineer
The Wollongong Group, Inc.
cjl (see nothing wrong with the way it works right now)
[Note, if they're reading this, I hope they won't mind me poking a little
fun at these early days.]
Anyway, I was having this problem where I'd run the program the first
time after a boot and it would work fine. Then I'd run it again, and it
would work fine again. The third time, however... *thud*. The machine
would lock up.
I worked on this thing for several days. Finally, I hypothesized that
DOS must be getting overwritten somewhere. DEBUG had copy and compare
memory commands, so I made a copy of low memory, ran the program, and
compared the current contents of low memory to my earlier copy. Then
(joy!) I ran through all the differences and compared the addresses
to known DOS variable areas. Luckily, I was able to locate a suspicious
looking modification.
Then I went into an iterative process where I rebooted, debugged the
program, executed so far into the program, made the copy of memory,
ran some more of the code, and compared my suspicious address to see
if it had been overwritten yet. Each time, I would narrow the range
of code being executed.
Eventually, I localized the memory overwrite. The whole thing was
caused by a missing declaration for malloc() (or whatever our allocation
layer was called then). The source code was something like:
char *p;
p = malloc(nnn);
*p = <something>;
Because there was no declaration, the C compiler assumed malloc()
returned an int in the AX register (16 bits). malloc() was actually
returning a 32 bit pointer, of course, in BX and AX. However, because
the code seemed to assign an int to a pointer, the compiler helpfully
zeroed the high order half for me (thus zero-extending the "int" into
a pointer), which caused the pointer to point to low memory somewhere.
Thanks a lot.
The whole process took me about a week. After I found the problem,
I discovered other places where this was being done so I wrote a long
memo describing the problem and extolling the virtues of declaring your
functions before calling them. So everyone started fixing their code,
right? Well, sometimes my suggested solution lost something in the
translation and I started seeing "fixes" like the following:
char *p;
p = (char *)malloc(nnn);
*p = <something>;
Sigh. :-)
--
Edmund Burnette, SAS Institute Inc. (919)677-8000 | sas...@unx.sas.com
SAS Campus Drive, Cary, NC 27513 (919)677-8123(fax) | ...!mcnc!sas!sasebb
I take exception to this. I'm a C people, and I have definitely argued that
depending on the quirks of implementations is sheer laziness. The standard
is pretty well defined, and coding for the standard is pretty reliable.
People who assume that int==32 bits or sizeof(int) == sizeof(long) should be
forced (as I have commented in the past) to port a few of the bigger crawling
horrors on the net (Emacs, say) to Xenix-286. That'll straighten them out in a
hurry!
It's more than Applesoft BASIC, it's in ALL early Microsoft BASIC.
For that matter, it's not even limited to MS-BASIC. MS-BASIC just used the
old FORTRAN parsing mechanism (i.e. ignore spaces).
+---------------
| 100 IF APPLES = ORANGES THEN GOTO 200
|
| The OR is a reserved word, and gets tokenized. When the interpreter encounters
| this line, the likely result is a syntax error. If the column width is set
| high enough, the computer will insert a space after the OR, and the
| reserved word sticks out like a sore thumb. However, novice users still don't
| get it, and advanced users always set the column width to 33 characters so
| that the computer will NOT insertspaces.
+---------------
...and the OSI C1P never inserted spaces (it only had a 22-character screen).
Even MORE diabolical.
+---------------
| Ask me about the UNIX C program I wrote that compiled flawlessly, but
| generated core dumps before executing even the FIRST LINE of my code.
+---------------
I've had that happen, too. Only thing is, I'd compiled in the Xenix
environment (the program was targeted for ncoast, but I was using a machine at
the office running a somewhat bastardized SCO UNIX). Apparently the
bastardizations killed its ability to run Xenix 386 binaries....
++Brandon
(P.S. Actually, it didn't even core dump: the kernel wanted to but it was so
confused that it didn't.)
--
Brandon S. Allbery, KF8NH [44.70.4.88] all...@NCoast.ORG
Senior Programmer, Telotech, Inc. (if I may call myself that...)
As regular readers of comp.std.c could tell you, I also find it very
difficult to believe anybody would design C.
--
Norman Diamond dia...@jit081.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.
"Yeah -- bad wiring. That was probably it. Very bad."
The problem was that occasionally a program would crash when using a
dynamically loaded object. The dynamic loading code was suspected as being at
fault, but all tests using other programs gave it a clean bill of health, and,
more over, putting debugging printf()s in the crashing code causes the crash
point to move! After some months of searching, I managed to isolate one
particular crash to a single assignment statement. The crash was occurring at
the point where the value was being assigned to a global variable. Most
strange.
The problem turned out to be this:
To turn a normal object file into a dynamic one, it is statically linked with a
version of libc.a which contains only those functions NOT exported by the
Andrew runtime system (which also contains the common objects mentioned above).
This is done by a program called doindex, which dynamically loads the .o file,
links it to the library, and then writes out the dynamic object, symbol table
and all.
The global variable that caused the crash I managed to isolate was an
uninitialized one, so it was being put in the .bss section of the .o file. The
dynamic loading code was working correctly on this section, creating space for
it and putting the absolute address in the symbol table so things could link to
it later. However, this memory allocation was being performed in doindex,
which was then writing out the absolute value for the variable into the dynamic
object because that was what the symbol table contained. This absolute value
was, of course, utter garbage inside the Andrew process, so things would
eventually fall over. The solution was a one line change to doindex which told
the dynamic loader not to allocate space for the .bss so the symbol table would
be correct.
Can anyone beat a wild pointer that went across completely unrelated processes?
--
Malcolm Purvis (malc...@otc.otca.oz.au)
Contractor, OTC R&D Section.
OTC, Sydney, Australia.
>As Bob Harper can attest to, some of my real-time code had to be debugged
>with an oscilloscope probe, [... rest deleted]
This reminds me of my EE 537 project. Since there was lots of hardware
which was designed and constructed by myself and my partner, the natural
place to start was the hardware.
The problem: writes to the interface board were not resulting in an output
of any sort. (Reads weren't working either, but we hadn't gotten to that
just yet)
We found that all of our latching hardware was producing, and responding to
the right timing signals. Still, no data on the latch.
Well, tracing the problem from the both the software and hardware ends,
we eventually came to the system bus.
For some reason, the 8 bits we were
writing, weren't making it to the lower 8 bits of the system bus.
After determining this via liberal use of a logic analyzer, I dug through
the 68000 reference book (not produced by motorola... a third party
book). Apparently, (how I could have missed something like this is
anyone's guess) when you access location $60000 for an 8 bit write,
the bits go on data bus lines 8-15, not 0-7. Silly me. Changing the $60000
to $60001 fixed the problem.
Grate. Relly grate.
Two events of interest here:
a. A rather violent thunderstorm cut the power and down we went.
When the system came alive again, APL restart failed in a very
odd fashion: I/O error reading record 0 of our accounting disk file.
Since we couldn't bill previous usage for the entire day if that
file was damaged, we all got this very sick feeling in the pits of
our stomachs. This was made worse by the fact that the code was
trying to read record 0 (360 user data records are origin 1). Something
was afoot!
So, we got out listing and single stepped through the initialization
code, as the phone rang off the wall from disgruntled users.
We got to the place where it turns a logical record number into a cylinder
number, head number, and physical record number, and then got confused:
We ended up with zero again. Very Strange.
Hmmm. Let's this again. Handpatch register contents back in. Check the
main store location of interest, to be sure it's still a divide. Yup.
Back up the PSW to retry the divide. Zero again. Very Very Strange.
Let's try something simple. Lessee here. Let's divide 10 by 5. Zero.
Oops! Let's divide a larger number by 2. BANG! Red lights all over the
console.
It turned out that the divider was broken, but the parity checking
logic wasn't bright enough to follow the divide logic all the way
along, so the divider reconstructed the parity coming out of the
divide circuit: The divider could produce any answer, and it would be
valid!
CE time: Replaced the offending card(s?) and were back on the air..
b. The 360/75 console had bathandle switches for performing mainstore
and register display and patch functions. (For you youngsters,
this was after the invention of TV, but they had not been hooked up
to computers yet in any big way (like letting you type in hex)).
These switches (there were about fifty or more of them) had multiple
sets of contacts, all of which liked to get dirty. For example, one
set was used to generate data bits. Another set was used to generate
the parity bits which went along with said data.
If one switch had one dirty contact, but not the other, patching
main store would cause red lights and a machine check interrupt,
which would crash things if you weren't careful.
The /75 also had an engineering change to fix up the lamp intensity for
the "lamp test" button which you HAD to use on each display,
as the lamp death rate was about 10 per day in normal use. The
EC dropped the lamp intensity during lamp test (1200lamps*x milliwatts
per lamp), to prevent tripping a breaker and taking the machine down
when you hit lamp test.
Those lamps cost a few bucks each, back in the late 1970s, as I recall.
Bob
Robert Bernecky r...@yrloc.ipsa.reuter.com bern...@itrchq.itrc.on.ca
Snake Island Research Inc (416) 368-6944 FAX: (416) 360-4694
18 Fifth Street, Ward's Island
Toronto, Ontario M5J 2B9
Canada
And don't forget
char *p2 = int i = char *p1, p2 == p1
Lots of code seems to assume that it is safe to dump a pointer into an int
and later retrieve it into another pointer. Programming in large-code or
large-data memory models (i.e. anything but Tiny, Small, or Flat) on an
Intel 80x86 machine will cure that misconception in a hurry....
--
{backbone}!cs.cmu.edu!ralf ARPA: RA...@CS.CMU.EDU FIDO: Ralf Brown 1:129/26.1
BITnet: RALF%CS.CMU.EDU@CARNEGIE AT&Tnet: (412)268-3053 (school) FAX: ask
DISCLAIMER? Did | Hansen's Library Axiom: The closest library doesn't
I claim something? | have the material you need.
Sorry, but that's the way it is. :-| I've never heard of any Basic
that had "TRUE" and "FALSE" predefined.
The real problem is not with TRUE and FALSE not being predefined, of
course, but with Basic allowing you to use variables without declaring
them first.
I've had similar problems: In GWBASIC, I tried to use some function
FOO (I've forgotten the actual name) that was in the standard library
of one Basic I was used to. To my horror, I found that FOO(X) always
returned a zero. Why? Because FOO wasn't predeclared in GWBASIC, so
the well-meaning compiler declared it as a 10-element array for me and
initialized it to zero. Arrrgh!
The canonical example of unintentional new variables is in Fortran,
where you also don't have to declare your variables before using them.
So, for example, the following routine to compute n! will give a very
unexpected result:
NFACT=1
DO 10 COUNT=1,N
10 NFACT=NFACT*C0UNT
Did you spot the error? Well, maybe you did, if your terminal uses a
sensible font: The second instance of "COUNT" was misspelled with a
zero instead of a letter "O". This is *not* discovered by the
compiler, that gladly assumes you really want a new variable and
creates it for you.
Some older Fortran programmers actually mean this is a *feature*, not
a bug:
Fortran programmer: "Those new languages like Pascal and C are so
tedious, you have to declare all your variables before you use them.
How silly!"
Me: "But, on the other hand, in Fortran you're in for trouble if you
misspell a variable; the compiler won't catch it"
F: "Of course, but you can't be that sloppy; you must proofread your
program carefully before entering it into the computer!"
This conversation took place in 1989!
Newsgroups: alt.folklore.computers,comp.lang.misc,comp.bugs.misc,comp.programming
Subject: Re: Trawl for debugging anecdotes
Summary:
Expires:
References: <1992Mar10.1...@uniwa.uwa.oz.au> <1992Mar11....@leland.Stanford.EDU> <1992Mar12.1...@daimi.aau.dk>
Sender:
Followup-To:
Distribution:
Organization: Theoretical Physics, Lund University, Sweden
Keywords:
In article <1992Mar12.1...@daimi.aau.dk> prot...@daimi.aau.dk (Lars J|dal) writes:
During my first programming job out of school, I was really not
into hardware. A new project started with the customer's own
prototype hardware. It was a z80 in an STD bus with some fairly
standard I/O. I was given a development machine, which could
assemble code and burn EPROMS. The prototype came in, and I had
a written test code to demonstrate simple I/O. My code polled
the serial port for input, and echoed it. It was burned into
EPROM. We hooked up a terminal, and it worked as you'd expect.
With that under the bridge, I wrote similar test code demonstrating
interrupt I/O. It did nothing. The polled I/O still worked.
There did not appear to be anything wrong with the code.
The customer was called in to examine the situation - he was the
hardware guru, after all. It turns out that his most powerful
diagnostic tool was a multimeter - in particular, a voltmeter.
He traced it down to the grounds for the +5 and +12 volt supplies
not being tied together. I recall that there was some 27 volts
difference. He tied the grounds together with an alligator clip
and everything worked.
I came away amazed that anything could have worked, including the
polled I/O. Hardware is basically magic, after all.
Curiously, the development hardware also suffered from power supply
related woes, and had a MTBF of about 45 minutes.
Stephen.
sui...@ima.isc.com
if( (a = (double **) malloc( (m+1) * sizeof(double *)) ) == NULL) /* first,...
return NULL;
if( (a[0] = a[1] = (double *) calloc( m*n, sizeof(double)) ) == NULL) /* get...
With this printout in hand, I spent hours on the phone with this guy, and
eventually we narrowed down the bug to the section of code above and began to
think that his malloc was broken... The next day he brought in a listing
with lines wrapped instead of truncated, and I immediately saw that the
comment /* first, ... had no closing */, thereby commenting out the next
two lines of code until the end of the /* get... comment.
He hit himself on the head for this one. I did too, and the dumb printer.
...Rick pe...@vu-vlsi.vill.edu, pe...@ucis.vill.edu
Dr. Rick Perry, Department of Electrical Engineering
Villanova University, Villanova, PA 19085, 215-645-4969, -4970, hm: 259-8734
Well, I guess my ripe old age of 31 is showing. FORTRAN H (running on an
ITEL AS/6 in 1979) was quite happy to do this. On to the horror story:
In 1979, I worked as a Programming Consultant (aka "Debug Desk Guy")
at Iowa State University. One poor sap brought in what I always called
a "Grad Student Program": someone had written the original in 1959, in
FORTRAN II, no less, and every summer, some grad student had the job
of adding in a feature. This program consisted of a 32000 line main
program and one subroutine
SUBROUTINE REASSIGN(X,Y)
X=Y
END
Whenever the program wanted to refine an iterative approximation, it would
call reassign with a constant and the new value for the constant.
The grad student in 1979 finally overflowed the Fortran H dimensional limits,
and had to split it into multiple routines. Unfortunately, when you compile
the routines separately, the literal spaces get split, and changing 1.271893
in one routine won't change the value of 1.271893 in any other routine.
Don't know if he ever got it fixed . . .
Kevin Wayne Williams
UUCP : ...!ames!ncar!noao!asuvax!gtephx!williamsk
Remember : Brute force has an elegance all its own.
\begin{rumour}
IBM has been using an APL to ADA translator for some time for various
"federal systems". One of them is reputed to be the Patriot missile control
system. The initial system shipped to the Gulf was in ADA. A person
involved with that system told me that "the ADA didn't run too much slower
than the APL code". Further rumour has it that a later shipment to the
Gulf was APL code, not ADA, because of the Need To Get It There Now.
\end{rumour}
If so, I should get cracking on making APL systems considerably faster.
My microcomputer Pascal compiled the program and it worked - in the
sense that I couldn't make it break.. But moving to my Alma Mater's
mainframe, a Burroughs (maybe something like 8700; badly outdated even
then), it wouldn't even compile! My GOTO pointed INSIDE A LOOP in the
main program, which is A Mortal Sin in standard Pascal (and probably in
every other language as well).. Later, when I told this folly of my
youth, a colleague wryly commented "And sometimes you manage to change
trains on the fly, too". Which in a way shows the dexterity needed to
make my original, sinister scheme work in the microcomputer.. :-)
(Since then I have repented and found Enlightenment; see .sig below.)
Internet: Matti....@Helsinki.FI Department of Computer Science
Voice: +358-0-708 4207 University of Helsinki,Finland
FALSE we know is 0, so say
CONST FALSE=0
CONST TRUE = NOT FALSE
|> You are lucky. The FORTRAN compilers for the DecSystem-10, running
|> TOPS-10, all exhibited this behaviour---as demonstrated by a bug I
|> found hellish to resolve.
|TOPS-10 had memory protection, but only one segment, the "high" segment
|which was intended for code. Only the high segment could be shared so
|DEC put the runtime system into the high segment to be shared by all
|Fortran users. The program private code went into the unshared data
|segment.
Not just Fortran users. I remember an old DEC machine that did the same
thing to me in a PL/I program -- after a certain point in the run, every
occurrence of the constant 1 in my code mysteriously acted like a 2.
Not an easy problem to track down...
>(If TRUE and FALSE really isn't meant to be defined in BASIC then
>pardon me because then there is no fun. But unless somebody explicitly
>tells me "that's the way it is" I find it very difficult to believe
>anybody would define a language which know of boolean operators but
>does not know TRUE and FALSE)
Actually, I've never used a BASIC that *HAD* pre-defined TRUE and FALSE
identifiers. Further, C, which has boolean operators, has no TRUE and
FALSE reserved words -- TRUE == !FALSE, and that's just the way it is.
Generally, TRUE and FALSE are defined in some header file as "manifest
constants".
--
Daniel A. Glasser One of those things that goes
d...@gorgon.UUCP "BUMP! (ouch!)" in the night.
It's not a mortal sin in C, though; consider Duff's device (if you dare!)
++Brandon
>In article <1992Mar11....@sparky.imd.sterling.com> d...@IMD.Sterling.COM (David Boyd) writes:
>>In article <1992Mar10.2...@cunixf.cc.columbia.edu> las...@watsun.cc.columbia.edu (Charles Lasner) writes:
>>>
>>is problems like the above and the FORTRAN glitch that started this thread
>>which prompted the Government to build Ada. Unfortunately Ada has gone
>>so far to the strict type checking extreme that it is very hard or cumbersome
>>to do many of the things that are easy to do in C and with all the run-time
>>type checking will require triple the execution time. I personnally think
>\begin{rumour}
>IBM has been using an APL to ADA translator for some time for various
>"federal systems". One of them is reputed to be the Patriot missile control
>system. The initial system shipped to the Gulf was in ADA. A person
>involved with that system told me that "the ADA didn't run too much slower
>than the APL code". Further rumour has it that a later shipment to the
>Gulf was APL code, not ADA, because of the Need To Get It There Now.
>\end{rumour}
>If so, I should get cracking on making APL systems considerably faster.
\begin{rumor}
All patriot missliels fired during the gulf war missed.
\end{rumor}
* These opinions belong to p...@mundil.cs.mu.OZ.AU unless otherwise specified.
"Such energies correspond to velocities of almost 95% of the speed of light,
far faster than the speed of sound." - Scientific American, Nov. 1991. p.34
In article <1992Mar12.1...@daimi.aau.dk> prot...@daimi.aau.dk (Lars J|dal) writes:
>(If TRUE and FALSE really isn't meant to be defined in BASIC then
>pardon me because then there is no fun. But unless somebody explicitly
>tells me "that's the way it is" I find it very difficult to believe
>anybody would define a language which know of boolean operators but
>does not know TRUE and FALSE)
Sorry, but that's the way it is. :-| I've never heard of any Basic
that had "TRUE" and "FALSE" predefined.
Or C, for that matter.
/===========================================================================\
|John (Francis) Stracke |My opinions are my own. |
|Natl. Science Center Foundation|===========================================|
|Augusta, GA | You buttered your bread, now lie |
|fra...@dogwood.atl.ga.us | in it. |
\===========================================================================/
(Formerly fra...@zaphod.uchicago.edu)
--
--
DWIM---and presumably other "intelligent" error correction systems, can
sometimes be too smart, frustrating the user. Here is one user's
description of the problem:
One especially annoying thing that DWIM can do is this: You are
composing Lisp code and in true Lisp tradition, you want understandable
variable and function names. Suppose you define and call a function
"(get-next)." DWIM sees the expression and helpfully decides that you
have made a typing error: You clearly mean to subtract "next" from
"get" but forgot both the spaces and also the proper Lisp notation
that requires the action to be listed first. So, DWIM politely,
elegantly transforms your name "(get-next)" into the Lisp code
"(minus get next)." When you try to run the program, you get an
error message: "get" was discovered to be an unbound variable, found
while Lisp was executing IDIFF, the routine for taking differences
between integers. .... the first few times it happens, it can be
very difficult to debug. Remember you never though you mentioned
a variable "get" and perhaps you didn't do any subtraction. Worse
yet, maybe you did do some subtraction, and so you waste much time
trying to fix the place in your program where you were subtracting.
Argghhhh!
[Claton Lewis and Donald Norman, ``Designing for
Error,'' in _User Centered System Design,_ Norman
and Draper, editors, Chapter 20, p. 425.]
Mike
--
J. Michael Lake Beckman Institute for Advanced Science and Technology
Dept. of Comp. Science jml...@uiuc.edu Urbana, IL 61801
>In article <1992Mar12.1...@daimi.aau.dk> prot...@daimi.aau.dk (Lars J|dal) writes:
>>(If TRUE and FALSE really isn't meant to be defined in BASIC then
>>pardon me because then there is no fun. But unless somebody explicitly
>>tells me "that's the way it is" I find it very difficult to believe
>>anybody would define a language which know of boolean operators but
>>does not know TRUE and FALSE)
>Sorry, but that's the way it is. :-| I've never heard of any Basic
>that had "TRUE" and "FALSE" predefined.
Ever heard of GFA Basic (GFA Systemtechnik, don't have the address handy)
>The real problem is not with TRUE and FALSE not being predefined, of
>course, but with Basic allowing you to use variables without declaring
>them first.
GFA Basic has a more elegant way to prevent you from inadvertently creating
new variables: You may set up the editor such that it alerts you each time
you type in a new variable, asking you whether you really intended to creata
it or it was just an error.
> [fortran stuff deleted]
Jan Kim X.400: S=kim;OU=vax;O=mpiz-koeln;P=mpg;A=dbp;C=de
Internet: kim%vax.mpiz-koe...@relay.cs.net
How about debugging hardware?
A couple of years ago, I was doing technical support for a company involved in
satellite communications for the trucking industry. This kind of operation is
not cheap: the trucking companies would pay on the order of $40K per year for
the account with the satellite company alone, plus a grand or two for each
truck. Our software was only used at the dispatch office, on an AT, and would
automatically call the satellite company for the data, display the truck
positions on a map, and handle the messages back and forth to the drivers. We
were the least expensive part of the system, and people sttill tried to chisel
the cost of the system down a few dollars. We only supported one brand of
modem: the truckers would try to use any old modem they had in the shop. In
one case, they were having trouble installing the software, because they were
trying to use an "abandoned" AT which had sat in the truck bay for 3 years,
and the floppy drives were so badly clogged with dirt that they would not read
the disks.
One "bug" that we eventually got to know quite well drove us crazy the first
time we encountered it. A new installation said they were getting a number of
"emergency" messages from the drivers. At the same time, none of their messages
were getting out to the field. When we asked about the content of the emergency
messages, they couldn't tell us.
The reason we only supported one brand of modem was that, in order to ensure
integrity of the data, we took over control of the modem in hardware when we
used it.
Because most of the customers used a "dial-up" connection to the satellite
company, rather than a leased line, "emergency" messages were the only time
that the satellite company initiated the call to the customer.
In this case, the trucking company had decided to save $15 on the price of a
serial cable between the AT and the modem, using instead an old cable from a
VT100 terminal. Terminal cables often have only 4 pins connected: we,
controlling the hardware, used eight.
When the customers machine (running our software) came to the point of a
pre-scheduled call, it checked the modem, and found it ready. It then started
to initiate the call, but also checked for incoming calls, so as not to conflict
with emergency messages. The RI line, by default, is pulled high, and without
the modem connection to pull it down, shows that the line is ringing. At this
point, the program (knowing that the only time the call would be initiated
from outside is when an emergency message was coming through) would flash up
an announcement (in a very "loud" red screen) of an emergency message, and
would try to answer the call. Of course, with no call coming in, the
connection would fail. Therefore, no call ever succeeded.
Of course, once we had determined this, the "emergency calls" were a dead
giveaway to the problem. All we had to hear on a call was "emergency messages"
and we told the caller to buy a proper serial cable.
==============
Vancouver | "A ship in a harbour
Institute for Robert...@sfu.ca | is sbut that is
Research into rsl...@cue.bc.ca | not what ships are
User CyberStore Dpac 85301030 | built for."
Security Canada V7K 2G6 | John Parks
-------------------------------------------------------------------
Richard Hempsey at rich%kno...@ersys.edmonton.ab.ca (preferred)
or ri...@ersys.edmonton.ab.ca
-------------------------------------------------------------------
>He hit himself on the head for this one. I did too, and the dumb printer.
I would have hit him on the head with the dumb printer too :-)
Jon Rosen
About a year and a half later, I had passed my operators course and
was hired by this client to help operate their brand new mainframe.
The building was an old, WWII temporary building, and still had a very
smooth, very long (about 300 ft) linoleum floor between the computer
room and the room where the backup disk packs and tapes were kept. On
my first evening shift, the operator and I had just finished making
the system backups and were walking the disk packs and tapes to
storage.
This is when he introduced me to the fine sport of curling.
--
|=================================================================| ttfn!
| Robert J Carter Oghma Systems Ottawa, Ontario | @ @
| Phone: (613) 565-2840 r...@oghma.ocunix.on.ca | * *
|=================================================================| \___/
We'd finally convinced these dudes to throw out their poxy Novell system
and install a decent network. The installation went well. Everything
worked. The users were happy.
A note about the system is in order. The fileserver was a 386 box with 2
hard disks. The vines server ran on Banyans own flavour of unix, and
there was no way to get at the underlying unix from the fileserver
[gnash gnash]. It turned out that this was one of the first Vines 386
systems with 2 hard drives in the world.
After a few days the users reported errors in some of their data. I was
despatched to investigate. Did all the usual things, everything looks
OK. Then I copied a large chunk of data on one of the drives into a
different directory. Part way through, I found data in the _source_
directory was getting corrupted.
There ensued a long period of bug tracking, complicated by the fact that
the electricians had installed the UPS too close to the fileserver and
the magnetic field from the transformer was corrupting the hard drives.
We moved the UPS, but the basic problem didn't go away. I re-installed
the network umpteen times. The dealers could not reproduce the problem
on their network. We replaced hard drives. We carted the dealers
fileserver in and ran our network on that. The bug stayed. The dealers
started coming up with helpful tips like "static - it must be static".
"Bollocks" says I [but I installed their anti-static gear all the same].
Banyan technical support are roped in at an early stage, and provide us
with the latest software patches. We low-level the drives and install
fresh systems yet again. The bug stays.
By this time I am thinking of joining a frequent flyer club, I've racked
up four weeks worth of overtime in as many months, and I'm on first name
terms with the staff at my hotel, not to mention the technical support
staff of our local Banyan dealer. The network was in the Treasury
department of company that turned over around a billion dollars
per year. They are getting nervous.
Finally, in the wee small hours on a weekend, when we'd rather have been
doing something else [anything else in fact]. One of the dealers techs
and myself re-created the bug on a different system. Install a 2 disk
system from scratch. Copy several megabytes of data from 1 disk to the
other - and everything turns to garbage.
When this happened we looked at each other. "Well" he said, "that's put
the brown stuff into the rotating device."
We told Banyan. Time passes. The Banyan people find a bug in their unix.
The OS automatically remaps bad blocks on the hard disk to a known good
area. This works fine on the 1st hard disk, but on the 2nd disk, the bad
blocks are remapped to the wrong place, corrupting data.
Why did it take so long to find? Firstly ours was one of very few
systems with 2 HD's, and a lot of the testing was done on single drive
systems. Sheer bad luck had a hand in it too. When we first tried to
reproduce the problem on another system, the second drive turned out to
be defect-free, thus the problem never occured.
Once this bug was exorcised, the network was very reliable.
| Geoff - Sysop Equinox (equinox.gen.nz) +64 (3) 3854406 (4 Lines)
| Email: ge...@satori.equinox.gen.nz
| "If I post something lucid, is that satorial eloquence?"
I used a cyber located in colorado at the time and was running some
data intensive icing models. The power in colorado seemed to go out
at the worst possible times, so they got a backup generator. Everything
seemed hunky-dory.
However, during this particular night I had *my* diskpack installed and
we were running on backup power, and everything was going fine until...
A drunk driver went off the road and through the fence taking out the
generator. I got a phone call saying that my *data* was all over the
inside of the drive, did I want them to sweep it up and send it to
me? Arggggh! I went back to my backup (a couple file cabinents full
of cards...) and started over. (sigh)
Its the only case I have heard of a job being killed by a drunk driver.
stuart galt boeing computer services
sag...@yak.boeing.com seattle washington
(206) 865-3764 or home (206) 361-0190
#include <standard/disclaim.h>
I don't know what they say, they don't know what I say...
Sorry, but that's the way it is. :-| I've never heard of any Basic
that had "TRUE" and "FALSE" predefined.
BBC Basic has had TRUE and FALSE built-in since its arrival about ten years
ago. (It also had procedures, functions, REPEAT-UNTIL, and arbitrary-length
variable names [*1] at that time; Basic V has also got properly nested
IF-THEN-ELSE, CASE, and WHILE. Pity about the data-structuring facilities.)
[*1] Module input line length being limited to 256 bytes, as I recall.
--
Regards | "Always code as if the guy who ends up maintaining your code will be
Kers. | a violent psychopath who knows where you live." - John F. Woods
(I keep two small plastic bugs on my workstation. These are the bugs I KNOW
about -- the others are in my code. :-)) Anyway,
I was in at work early one Saturday morning trying to get this firmware working
on this embedded controller product because a customer had a small problem (and
the salesman had gone non-linear about it). My emulator and equipment was on
the table behind me, and I was scanning a listing on my desk when the company
pres walks in to chat.
While we're talking, he says, "What's that on the table? Another one of your
bugs?" I turn around, "Huh? .... Oh JEEZ!" Here was a HUGE beetle kicking
around on top of a listing. It couldn't go anywhere because a firmware label
was stuck to two legs.
A firmware bug, obviously.
I suppose we could have sent it to the salesman as proof of our diligence, but
they usually have no sense of humor about that.
--
Clayton Haapala (cl...@mudlhead.network.com)
Network Systems Corp. "...and the alligators are on FIRE."
7600 Boone Ave N -- S.E.K.
Minneapolis, MN 55428-1099
DO 350 I=1.500
.
.
.
350 CONTINUE
Since spaces mean (meant?) nothing to the FORTRAN compiler, the undeclared
variable do350i was assigned the value 1.5, and the "loop" gets executed
once (with I having some unknown value.)
--
Christopher C. Evert lambdax.:-)xx labmdax.:-)xx
cev...@zeus.wg.waii.com "Leading lamb(da calculu)s
uunet!airgun!cevert to (the s)laughter."
Anyway, we tied our front-end screen-painter/forms package to our multi-user
server and logged two users into the system. Each attempted to add a record
(row in relational parlance :-) to a file that had exactly one record already
in it. The initial attempt appeared to work (both users got back OK signals
which suggested the code had worked properly). Both users logged out and
we ran a simple RAMIS report request to list the supposedly three records
now in the file.
Well, after waiting for several minutes for the report to come back (it
typically should have taken about 2 seconds or less), we killed the
execution. It occurred to me that the request we issued asked for the
report writer to gather all the data, sort it and then print it. So
I modified the request slightly to eliminate the sorting option and
have it report each record as it was retrieved. Well, I ran the new
test and it printed out:
KEY
---
RECORD 1
RECORD 2
RECORD 3
RECORD 1
RECORD 2
RECORD 3
RECORD 1
RECORD 2
RECORD 3
....
!!!&&$%####&@@@!!!##
The database had gone into a loop (read that again closely...) No, not
the program, the database itself had actually put itself into a loop!
RAMIS was implemented as a linked list of records and apparently, due
to a bug in the API routine supplied to us by the vendor, when we had
multiple paths open through a single file, the writes to the file would
collide and in this particularly instance, the pointer on RECORD 3
which should have pointed to EOF, actually pointed back to RECORD 1.
So, as the report writer tried to collect records, it just kept going
back through the same three records over and over again. We later
tried it and let it run indefinitely and it ultimately abended when
it ran out of temporary disk storage to put the three rows on (several
million times :-)
We had to wait till the next release for a bug fix (about 6 months) and
they indeed did make it work, but what a mess :-)
Jon Rosen
This reminds me of a discussion we had at college:
The ultimate error correcting compiler would generate a Database
Management System out of ... nothing!
--
| Josef Moellers | c/o Siemens Nixdorf Informationssysteme AG |
| USA: molle...@sni-usa.com | Abt. STO-XS 113 | Riemekestrasse |
| !USA: molle...@sni.de | Phone: (+49) 5251 835124 | D-4790 Paderborn |
My first ever attempt at debugging a program was on an ICL machine, in
FORTRAN. The program seemed to run but produced totally incorrect answers.
Diving things by 5 didn't produce the expected answer!
...
call test(i,5)
...
subroutine test(i,j)
...
j = 3
...
Unfortunately the compiler used that same location every time a 5 was
used in the code,
which is a optimization to save code space :-)
so after executing my routine all the 5s in the rest
of the program became 3s...
Ignatios
{ DisplayObject do = displayObject_nil;
...
}
It's a funny thing, but if you don't use a keyword for a few years you
can kind of foget that it's there (and the error messages for that one
were NOT clear).... Since then I've managed to have name collisions on
both "goto" and "char" (I needed a parameter of type Char, right? :-).
But now I figure it out almost immediately....
The sad thing about programming is, the harder you try, the worse it
works....
----------------------------------------------------------------------
stephen p spackman Center for Information and Language Studies
ste...@estragon.uchicago.edu University of Chicago
----------------------------------------------------------------------
I used such a system in the late 60's.
Allan Duncan ACSnet adu...@trl.oz
(+613) 541 6708 Internet adu...@trl.oz.au
UUCP {uunet,hplabs,ukc}!munnari!trl.oz.au!aduncan
Telecom Research Labs, PO Box 249, Clayton, Victoria, 3168, Australia.
Hmm...The TA's for my class don't care whether it _works_. Haha, heaven
forbid. No, it must be within 1 character or the Teacher's Example.
How many times have I gotten a 'this _can't_ work' with it's
corresponding -15 point markdown....sheesh.
--
evi...@vesta.unm.edu \ and when the wombat comes
AKBAR! =IC:D~ \ he will find me gone...
JEFF! =IC:D~ \
boogaboogaboogaboogaboogaboogaboogaboogaboogaboogaboogaboogaboogaboogabooga
As others have mentioned elsewhere in this thread, Microware's
BASIC09 for use under OS-9 has them, but also HP's Rocky Mountain BASIC (on
the HP9826 et. al.) has them.
--
Donald Nichols (DoN.) | Voice (Days): (703) 704-2020 (Eves): (703) 938-4564
D&D Data | Email: <dnic...@ceilidh.beartrack.com>
I said it - no one else | <dnic...@ceilidh.aes.com>
--- Black Holes are where God is dividing by zero ---
I always used to do something like this near the begining of the
BASIC programs:
30 TRUE = ( 1 = 1)
40 FALSE = ( 1 = 0 )
figuring that I couldn't be sure whether a different BASIC interpreter might
use a different convention for flaging TRUE and FALSE, but the interpreter
could be forced to set the values for me :-)
IF (X.EQ.Y) . . .
where X and Y are both REAL. X and Y may be algebraically equal but
fail the test due to rounding error.
There should be one exception, namely, when X and Y both result from the
same function call with the same arguments.
Guess again. In one program, the compiler recognized that Y was being
calculated only so that it could be compared to X and, therefore, kept
it in a register rather than assign it to a variable. Since registers
are allocated more bits of storage than variables, the test FAILED even
though both calculations were obtained by calling the same function with
identical arguments!
IF (X.EQ.Y) . . .
where X and Y are both REAL. X and Y may be algebraically equal
but fail the test due to rounding error.
Well, it's true that you should never use such expressions, but the
real reason is that X. and EQ. are undefined.
Also, the construct '. . .', while legal, is rarely used. What are
you using a triple dot product for?
All irony aside, please be careful about making broad, sweeping
statements like "everyone knows". As it happens there are computer
languages where the equality test on floating point numbers has been
given a meaningful definition.
Is it too much to ask you to specify what language(s) you're talking
about? [Presumably FORTRAN, in this case?]
--
Raul Deluth Miller-Rockwell <rock...@socrates.umd.edu>
We had a very strange error mode on a VAX 11/785: the unix linker (ld)
would terminate silently without producing any code, or generate code
that core-dumped rather quickly - but only when compiling programs
larger than 32k. Of course all of DEC's diagnostics ran perfectly
well...
This ended up being a rather strange bug in the memory cache controller
caused one bit to flip; the interesting part is that the result was to
change an "add" instruction into a "mov", which has exactly the same
operands format - it executed flawlessly, but generating the wrong
results! (Another interesting aspect is that a news article in
comp.sys.misc is what convinced the DEC techs that it was their
hardware's fault; our management never asked "what do you need this
space-eating news system for" again...)
The other one is not by personal experience, it's probably an urban
legend among chip makers: A fab noticed their yields were dropping
sharply on batches run on Mondays. Finer analysis showed organic
contamination. The mystery was solved when an engineer stayed over the
weekend to see what was going on; it seems some ovens were left
unoccupied, so the cleaning staff used them to make pizza!
--
Amos Shapir am...@cs.huji.ac.il
The Hebrew Univ. of Jerusalem, Dept. of Comp. Science.
Givat-Ram, Jerusalem 91904, Israel
Tel. +972 2 585706 GEO: 35 11 46 E / 31 46 21 N
It can take a touch typist a LONG TIME to realise that the keycaps are
on wrong....
Well, APLers use the above form (x = y) a LOT, and without problems,
on floating and complex arguments. Why does it work for them and not
for C or Fortran programmers?
Because APL has a concept known as "tolerant comparison" which
changes the behavior of the relationals, floor, and residue.
I'll give the definition of equality, and you can work out the
others or check the literature for the remainder.
teq: (abs x-y) .LEQ. quadct * (abs x)max abs y
where .LEQ. is exact less than or equal, and quadct is a small non-negative
real number.
Tolerant equality masks the effect of small floating point errors,
by allowing nearly-equal numbers to be treated as equal.
quadct is alterable by the user, and setting it to zero gives you
exact comparisons.
tolerant comparisons are also used in set membership and "indexof"
(table lookup).
The approach works quite well in practice. Most people never alter the
default value of quadct, which is typically about 1e_14.
Robert Bernecky r...@yrloc.ipsa.reuter.com bern...@itrchq.itrc.on.ca
Snake Island Research Inc (416) 368-6944 FAX: (416) 360-4694
18 Fifth Street, Ward's Island
Toronto, Ontario M5J 2B9
Canada