Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.compilers > #3500 > unrolled thread
| Started by | gah4 <gah4@u.washington.edu> |
|---|---|
| First post | 2023-07-10 19:42 -0700 |
| Last post | 2023-07-17 13:09 +0200 |
| Articles | 8 — 4 participants |
Back to article view | Back to comp.compilers
modifying constants in Fortran and elsewhere gah4 <gah4@u.washington.edu> - 2023-07-10 19:42 -0700
Re: modifying constants in Fortran and elsewhere Thomas Koenig <tkoenig@netcologne.de> - 2023-07-15 10:57 +0000
Re: modifying constants in Fortran and elsewhere Hans-Peter Diettrich <DrDiettrich1@netscape.net> - 2023-07-16 11:56 +0200
Re: modifying constants in Fortran and elsewhere Thomas Koenig <tkoenig@netcologne.de> - 2023-07-16 13:08 +0000
Re: modifying constants in Fortran and elsewhere gah4 <gah4@u.washington.edu> - 2023-07-16 19:09 -0700
Re: modifying constants in Fortran and elsewhere gah4 <gah4@u.washington.edu> - 2023-07-17 10:51 -0700
Re: modifying constants in Fortran and elsewhere gah4 <gah4@u.washington.edu> - 2023-07-16 19:17 -0700
Re: modifying constants in Fortran and elsewhere David Brown <david.brown@hesbynett.no> - 2023-07-17 13:09 +0200
| From | gah4 <gah4@u.washington.edu> |
|---|---|
| Date | 2023-07-10 19:42 -0700 |
| Subject | modifying constants in Fortran and elsewhere |
| Message-ID | <23-07-003@comp.compilers> |
A potential bug since the earliest days of Fortran is passing a constant to a subroutine, and then changing the value of the dummy argument. In at least some Fortran system, this modifies the value of a constant used other places in a program. As this was known when PL/I was designed, it is defined such that modifiable constants are passed to called procedures. C avoids it by not allowing the & operator on constants. (Though K&R allows modification of string constants.) Somehow, in all the years, that feature was never added to Fortran. It is easy to write programs and test for it, but I wonder if there are any stories for real program that had this bug, and even better, stories about the difficulty of finding it, or problems caused by it.
[toc] | [next] | [standalone]
| From | Thomas Koenig <tkoenig@netcologne.de> |
|---|---|
| Date | 2023-07-15 10:57 +0000 |
| Message-ID | <23-07-006@comp.compilers> |
| In reply to | #3500 |
gah4 <gah4@u.washington.edu> schrieb: > A potential bug since the earliest days of Fortran is passing a > constant to a subroutine, and then changing the value of the dummy > argument. > > In at least some Fortran system, this modifies the value of a constant > used other places in a program. Could come in handy if the value of PI should change during the excecution of the program :-) This is a consequence of the standard /360 calling convention. Both arguments and local variables were put in close proximity to the code, if posssible within the range of a base register. It was all read-write, and the compiler optimized duplicate constants. (The explanation above is only for non-reentrant code, which was the usual case for FORTRAN, but they could be made to use reentrant code using a compiler option). > As this was known when PL/I was designed, it is defined such that > modifiable constants are passed to called procedures. C avoids it by > not allowing the & operator on constants. (Though K&R allows > modification of string constants.) You can still try by passing a pointer to a const variable, but chances are you will get a segfault when you try to modify it. > Somehow, in all the years, that feature was never added to Fortran. Fortran has the VALUE attribute for dummy variables now, which generates a local copy of the variable. Compilers differ on how they implement it; passing VALUE arguments as actual value, like C usually does, or passing a pointer and making a local copy are both valid choices. > It is easy to write programs and test for it, but I wonder if there > are any stories for real program that had this bug, and even better, > stories about the difficulty of finding it, or problems caused by it. I actually got bitten by that while using a mainframe for scientific work as a student. It's been a few decades, so I don't recall too many details. It was difficult to find, but I was paid by the hour, so I didn't mind too much :-) [The constant stomping issue far predates S/360. As soon as Fortran II added subroutines on the 704, there were constant arguments you could change by mistake. The problem is that it took quite a while for people to sort out the differences among call by reference, call by value, and call by copy in/out. Fortran on the 70x and S/360 user reference for array arguments, copy in/out for scalars. Algol 60 tried to define its argument passing in an elegant way, and accidentally invented call by name when they meant call by reference. -John]
[toc] | [prev] | [next] | [standalone]
| From | Hans-Peter Diettrich <DrDiettrich1@netscape.net> |
|---|---|
| Date | 2023-07-16 11:56 +0200 |
| Message-ID | <23-07-007@comp.compilers> |
| In reply to | #3502 |
On 7/15/23 12:57 PM, Thomas Koenig wrote: > gah4 <gah4@u.washington.edu> schrieb: >> A potential bug since the earliest days of Fortran is passing a >> constant to a subroutine, and then changing the value of the dummy >> argument. > I actually got bitten by that while using a mainframe for scientific > work as a student. It's been a few decades, so I don't recall too > many details. It was difficult to find, but I was paid by the hour, > so I didn't mind too much :-) I remember such a bug in the 80s on the pdp-11/34 of our institute. > Algol 60 tried to define > its argument passing in an elegant way, and accidentally invented call > by name when they meant call by reference. -John] By Name example from the German wikipedia <https://de.wikipedia.org/wiki/Namensparameter> >> A[1] := 10 A[2] := 20 i := 1 x := Funkt (A[i], i) FUNCTION Funkt (a, i) : Real i := i+1 RETURN a END x wird der Wert 20 zugewiesen. Im Werteparameter-Fall wäre x dagegen 10, ebenso bei Referenzparametern. << Returns 20 as ByName while 10 were returned for ByRef. DoDi [Then there's the infamous Knuth Man or Boy program, where even he couldn't figure out what the answer was supposed to be. https://en.wikipedia.org/wiki/Man_or_boy_test -John]
[toc] | [prev] | [next] | [standalone]
| From | Thomas Koenig <tkoenig@netcologne.de> |
|---|---|
| Date | 2023-07-16 13:08 +0000 |
| Message-ID | <23-07-008@comp.compilers> |
| In reply to | #3502 |
Our esteemed moderator wrote: > [The constant stomping issue far predates S/360. As soon as Fortran II > added subroutines on the 704, there were constant arguments you could > change by mistake. The problem is that it took quite a while for people > to sort out the differences among call by reference, call by value, > and call by copy in/out. Fortran on the 70x and S/360 user reference > for array arguments, copy in/out for scalars. I just have the IBM System/360 Operating System FORTRAN IV (H) Programmer's Guide, Fourth Edition, open (isn't Bitsavers great?). It states, on page 108 Argument List The argument list contains addresses of variables, arrays, and subprogram names used as arguments. Each entry in the argu- ment list is four bytes and is aligned on a full-word boundary. The last three bytes of each entry contain the 24-bit address of an argument. The first byte of each entry contains zeros, unless it is the last entry in the argument list. If this is the last entry, the sign bit in the entry is set on. So, apparently no copy in/out on that particular compiler, at least. It also shows the (ab)use that was possible of the uppermost byte, because clearly 24 bits are enough for everybody and for all time, right? :-) [See the 360 Fortran IV Language manual, where on pages 90-95 it explains copy in/out and how to avoid it by putting slashes around the dummy argument names. https://bitsavers.org/pdf/ibm/360/fortran/C28-6515-7_System_360_FORTRAN_IV_Language_1966.pdf I was there, I actually used this stuff. Re abuse of the upper byte, as the size of OS/360 exploded way past what they expected, programmers were under pressure to make every bit and byte count, hence overloading the high byte. -John]
[toc] | [prev] | [next] | [standalone]
| From | gah4 <gah4@u.washington.edu> |
|---|---|
| Date | 2023-07-16 19:09 -0700 |
| Message-ID | <23-07-009@comp.compilers> |
| In reply to | #3504 |
On Sunday, July 16, 2023 at 9:43:20 AM UTC-7, Thomas Koenig wrote: (snip) > I just have the IBM System/360 Operating System FORTRAN IV (H) > Programmer's Guide, Fourth Edition, open (isn't Bitsavers great?). > > It states, on page 108 > > Argument List > > The argument list contains addresses of > variables, arrays, and subprogram names > used as arguments. Each entry in the argu- > ment list is four bytes and is aligned on a > full-word boundary. The last three bytes > of each entry contain the 24-bit address of > an argument. The first byte of each entry > contains zeros, unless it is the last entry > in the argument list. If this is the last > entry, the sign bit in the entry is set on. > So, apparently no copy in/out on that particular compiler, at least. > It also shows the (ab)use that was possible of the uppermost byte, > because clearly 24 bits are enough for everybody and for all > time, right? :-) Soon after I started learning OS/360 Fortran, I found the LIST compiler option. That gives a listing, sort-of, of the generated assembly code. (Not good enough to actually assemble, but useful to figure out what it actually does.) First, OS/360 Fortran, like just about all the others at the time, does all static allocation. The MAP option gives a listing of all the variables used, and their addresses. Each subroutine has a prologue, which copies all scalar variables to the address indicated in the map, and an epilogue which copies them back. Variables are stored just after the executable code, and so addressable with the same base register, as long as it fits in 4K bytes. (Or two or three base registers for 8K or 12K bytes.) Once copied, they are easily directly addressed. Otherwise, to use one, the address is loaded into a register, and then used, requiring usually two instructions. And two instructions to copy each in, and two more to copy back out. So any variable referenced more than four times, is faster with the copy. And yes, you can put the dummy argument between slashed, in which case it won't do that. There is one reason given by IBM. A DIRECT ACCESS statement, used with a direct access file, keeps a variable with the record number of the next record, in case you want to read sequentially. If you need to reference that from a called subroutine, you need the slashes. There are a few other cases involving variables in COMMON, such that a variable could change at an unusual time. In any case, the Fortran standard, since Fortran 66 allows for this. I didn't know until the above note from or moderator that went back to the IBM 704, where Fortran originated. I don't know the addressing modes of the 704, and how or why that helped. The only other compiler that I know in that much detail is Fortran-10 for the PDP-10. The PDP-10 has an indirect bit on addresses, such that the processor will indirectly address with one instruction, though likely the time of two instructions. It is only more recently, with non-contiguous assumed shape arrays, that this came back again. Fixed size and assumed size arrays are assumed by the called routine to be contiguous. If a routine with an assumed shape argument, calls another with assumed size, it is usual to make a copy and pass that. Then copy back again on return. In that case, it is the caller that does the copy, not the callee, as for IBM. [The 70x series had 15 bit word addressing with index registers. Even though they mostly did sign/magnitude arithmetic, indexing worked by doing a two's complement subtract of the index register from the address in the instruction. (I've seen lots of guesses why they did that, but never found an actual source.) So Fortran arrays were stored in reverse order starting in high memory. 70x Fortran did not have the /X/ argument specifier and I cannot find anything in the manuals about argument aliasing, although the calling sequence example in the FAP assember program shows how to copy in arguments. The Fortran manual does say: A constant may not appear as an argument in the call to a SUBROUTINE or FUNCTION subprogram if the corresponding dummy variable in the definition of the subprogram appeared either on the let side of an arithmetic statement or in an input list. -John]
[toc] | [prev] | [next] | [standalone]
| From | gah4 <gah4@u.washington.edu> |
|---|---|
| Date | 2023-07-17 10:51 -0700 |
| Message-ID | <23-07-013@comp.compilers> |
| In reply to | #3505 |
(snip, our moderator wrote) > [The 70x series had 15 bit word addressing with index registers. Even > though they mostly did sign/magnitude arithmetic, indexing worked by > doing a two's complement subtract of the index register from the > address in the instruction. (I've seen lots of guesses why they did > that, but never found an actual source.) So Fortran arrays were stored > in reverse order starting in high memory. 70x Fortran did not have > the /X/ argument specifier and I cannot find anything in the manuals > about argument aliasing, although the calling sequence example in the > FAP assember program shows how to copy in arguments. I have known for a long time that the 704 (and I believe later 7.. machines) indexes arrays backwards, and allocates from the end of memory. Allocating COMMON from the end of memory is convenient, in that is the one place (other than the beginning) where you know will always by the same. Indexing back means that it will still work, even with different length COMMON. One Fortran feature that I only recently found out about, from 1130 ECAP, is CALL LINK. A program can CALL LINK(other program name), and replace itself with another executable program. Not a subroutine call, but the whole program is replaced in memory. But COMMON blocks are kept! (That might be before subroutine overlay that I know well.) By the time of OS/360, that seems to have disappeared, but a fancy subroutine overlay system then appeared. I any case, allocating from the end of memory, and indexing backward, is convenient for aligning data in different whole executable programs. Maybe they were just lucky. [The 70x IBSYS had what they called chain jobs, same idea that the code was overwritten but the common data stayed. The 360 linker had an elaborate system of tree structured overlays that let you divide the code into segments loaded automatically when the program called a routine in the segment, again leaving whatever was in the root segment, typically including common blocks. You can read all about it in Chapter 8 of "Linkers and Loaders", available from better booksellers everywhere. -John]
[toc] | [prev] | [next] | [standalone]
| From | gah4 <gah4@u.washington.edu> |
|---|---|
| Date | 2023-07-16 19:17 -0700 |
| Message-ID | <23-07-010@comp.compilers> |
| In reply to | #3504 |
> Our esteemed moderator wrote: (snip) > I was there, I actually used this stuff. Re abuse of the upper byte, as the size of > OS/360 exploded way past what they expected, programmers were under pressure to make > every bit and byte count, hence overloading the high byte. -John] Funny how history repeats itself. (As the saying goes.) In this case, it was only the one bit, and with 31 bit addressing, it could still be used. Though the compile doesn't actually check for the end of the argument list. Much of OS/360, at all levels, uses the high byte of addresses. Most important, in the DCB used for much I/O. With the transition to 31 bit and 64 bit addressing, much of the old control blocks are still there. The DCB is in user address space, and so not easily replaced. Much of that is still true in OS/390 and z/OS, the 31 bit and 64 bit OS. And then years later, Apple creates the Macintosh, and (original) MacOS. And with 24 bit addressing on the 68000, uses the high byte of addresses. Then with the 68020, there were programs known to be 32 bit clean, and those that were not. I suspect that all the hard learned lessons from the mainframe days were relearned in the microcomputer days.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2023-07-17 13:09 +0200 |
| Message-ID | <23-07-011@comp.compilers> |
| In reply to | #3500 |
On 11/07/2023 04:42, gah4 wrote: > A potential bug since the earliest days of Fortran is passing a > constant to a subroutine, and then changing the value of the dummy > argument. > > In at least some Fortran system, this modifies the value of a constant > used other places in a program. > > As this was known when PL/I was designed, it is defined such that > modifiable constants are passed to called procedures. C avoids it by > not allowing the & operator on constants. (Though K&R allows > modification of string constants.) > > Somehow, in all the years, that feature was never added to Fortran. > > It is easy to write programs and test for it, but I wonder if there > are any stories for real program that had this bug, and even better, > stories about the difficulty of finding it, or problems caused by it. I don't think any language can beat Forth here: 1 . => 1 ok 1 1 + . => 2 ok : 1 2 ; => ok 1 . => 2 ok 1 1 + . => 4 ok If you want to redefine the meaning of a number, you just define it like any other identifier.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.compilers
csiph-web