[patch, fortran] New fix: PR31201 Too large unit number generates wrong code
FX Coudert
fxcoudert@gmail.com
Sun May 6 17:19:00 GMT 2007
Hi Jerry,
Sorry again for taking that much time to review your patch.
Unfortunately, it's still not OK due to the ERR specifier. If you
take code using a unit number that is too large, but wraps to a
positive int4 value, you can generate wrong code:
$ cat a.f90
integer :: i
character(len=60) :: s
open(2_8*huge(0)+20_8,file="foo",iostat=i)
print *, i
open(2_8*huge(0)+20_8,file="foo",err=99)
99 print *, "ERR worked ok"
write(18,*) "test"
end
$ cat foo
cat: foo: No such file or directory
$ ./bin/gfortran -static a.f90 && ./a.out
5005
ERR worked ok
$ cat foo
test
It so happens that the unit number in this code (2_8*huge(0)+20_8)
wraps into an integer(kind=4) with the value 18. Thus, writing later
to unit 18 actually writes for foo (instead of opening a fort.18
file). This shows that the OPEN statement is executed after your call
to generate_error. The code generated for this example show that:
_gfortran_generate_error (&open_parm.2, 5005, "Unit number in I/
O statement too large");
open_parm.2.common.unit = 18;
_gfortran_st_open (&open_parm.2);
switch (open_parm.2.common.flags & 3)
{
case 1:;
goto __label_000099;
}
The problem and the solution are clear: we should, after
_gfortran_generate_error is called, check the value of (open_parm.
2.common.flags & 3) exactly in the same way it is done after the call
to _gfortran_st_open. This is done with io_result(), which should
probably be called from gfc_trans_io_runtime_check().
I think this time, it's really the last hurdle. I have checked the
standard and thought carefully about IOMSG, EOR and END, to conclude
that they cannot be a problem in this precise case. I know that you
will be travelling next week, so if you submit a final patch, I'll
review it and commit under your name during that time. If you don't
have time to put up an updated patch before leaving, I'll try to do
it myself, as I think it's only a matter of a few code lines.
Thanks again for your work,
FX
PS: One minor remark: I think MAX_UNIT_NUMBER should be replaced by
the code I sent you to generate the maximal value of the unit type
(integer(kind=4)). The following code works fine for me:
+ /* If we're storing a UNIT number, we need to check it first. */
+ if (type == IOPARM_common_unit && e->ts.kind != 4)
+ {
+ tree max, cond;
+ ioerror_codes bad_unit;
+ int i;
+
+ bad_unit = IOERROR_BAD_UNIT;
+
+ /* Don't evaluate the UNIT number multiple times. */
+ se.expr = gfc_evaluate_now (se.expr, &se.pre);
+
+ /* UNIT numbers should be nonnegative. */
+ cond = fold_build2 (LT_EXPR, boolean_type_node, se.expr,
+ build_int_cst (TREE_TYPE (se.expr),0));
+ gfc_trans_io_runtime_check (cond, var, bad_unit,
+ "Negative unit number in I/O statement",
+ &se.pre);
+
+ /* UNIT numbers should be less than the max. */
+ i = gfc_validate_kind (BT_INTEGER, 4, false);
+ max = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].huge, 4);
+
+ cond = fold_build2 (GT_EXPR, boolean_type_node, se.expr,
+ fold_convert (TREE_TYPE (se.expr), max));
+ gfc_trans_io_runtime_check (cond, var, bad_unit,
+ "Unit number in I/O statement too large",
+ &se.pre);
+
+ }
More information about the Fortran
mailing list