This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, libgfortran] PR39665, alignment problems


Hello,

this patch hopefully works around the alignment problems reported in
PR39665. The problem is that nowadays when we read a floating point
number, it's stored into the result variable with an assignment. This
works fine for formatted reads, as the result variable is the final
variable passed in from the user code, so it always is sufficiently
aligned. However, for list formatted and namelist reads, we used a
temporary char* buffer, and some platforms like IA-64 or HP-PA are picky
about alignment and crash. This patch modifies list formatted and
namelist reads of real and complex type. Unfortunately the fix isn't as
clean as I'd wish, since after the parsing it turns out that the value
must be saved anyway in order to handle repeat counts.

Regtested on i686-pc-linux-gnu, Ok for trunk?


-- 
Janne Blomqvist
2009-04-09  Janne Blomqvist  <jb@gcc.gnu.org>

	PR fortran/39665
	* io/list_read.c (read_complex): Read directly into user pointer.
	(read_real): Likewise.
	(list_formatted_read_scalar): Update read_complex and read_real calls.
	(nml_read_obj): Read directly into user pointer.
	* io/read.c (convert_real): Add note about alignment requirements.
diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index 1637957..f6a4017 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -1224,7 +1224,7 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
    what it is right away.  */
 
 static void
-read_complex (st_parameter_dt *dtp, int kind, size_t size)
+read_complex (st_parameter_dt *dtp, void * dest, int kind, size_t size)
 {
   char message[100];
   char c;
@@ -1248,7 +1248,7 @@ read_complex (st_parameter_dt *dtp, int kind, size_t size)
     }
 
   eat_spaces (dtp);
-  if (parse_real (dtp, dtp->u.p.value, kind))
+  if (parse_real (dtp, dest, kind))
     return;
 
 eol_1:
@@ -1271,7 +1271,7 @@ eol_2:
   else
     unget_char (dtp, c);
 
-  if (parse_real (dtp, dtp->u.p.value + size / 2, kind))
+  if (parse_real (dtp, dest + size / 2, kind))
     return;
 
   eat_spaces (dtp);
@@ -1305,7 +1305,7 @@ eol_2:
 /* Parse a real number with a possible repeat count.  */
 
 static void
-read_real (st_parameter_dt *dtp, int length)
+read_real (st_parameter_dt *dtp, void * dest, int length)
 {
   char c, message[100];
   int seen_dp;
@@ -1518,7 +1518,7 @@ read_real (st_parameter_dt *dtp, int length)
   unget_char (dtp, c);
   eat_separator (dtp);
   push_char (dtp, '\0');
-  if (convert_real (dtp, dtp->u.p.value, dtp->u.p.saved_string, length))
+  if (convert_real (dtp, dest, dtp->u.p.saved_string, length))
     return;
 
   free_saved (dtp);
@@ -1762,10 +1762,16 @@ list_formatted_read_scalar (st_parameter_dt *dtp, volatile bt type, void *p,
       read_character (dtp, kind);
       break;
     case BT_REAL:
-      read_real (dtp, kind);
+      read_real (dtp, p, kind);
+      /* Copy value back to temporary if needed.  */
+      if (dtp->u.p.repeat_count > 0)
+	memcpy (dtp->u.p.value, p, kind);
       break;
     case BT_COMPLEX:
-      read_complex (dtp, kind, size);
+      read_complex (dtp, p, kind, size);
+      /* Copy value back to temporary if needed.  */
+      if (dtp->u.p.repeat_count > 0)
+	memcpy (dtp->u.p.value, p, size);
       break;
     default:
       internal_error (&dtp->common, "Bad type for list read");
@@ -1781,8 +1787,12 @@ list_formatted_read_scalar (st_parameter_dt *dtp, volatile bt type, void *p,
   switch (dtp->u.p.saved_type)
     {
     case BT_COMPLEX:
-    case BT_INTEGER:
     case BT_REAL:
+      if (dtp->u.p.repeat_count > 0)
+	memcpy (p, dtp->u.p.value, size);
+      break;
+
+    case BT_INTEGER:
     case BT_LOGICAL:
       memcpy (p, dtp->u.p.value, size);
       break;
@@ -2384,12 +2394,17 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
               break;
 
 	  case GFC_DTYPE_REAL:
-	      read_real (dtp, len);
-              break;
+	    /* Need to copy data back from the real location to the temp in order
+	       to handle nml reads into arrays.  */
+	    read_real (dtp, pdata, len);
+	    memcpy (dtp->u.p.value, pdata, dlen);
+	    break;
 
 	  case GFC_DTYPE_COMPLEX:
-              read_complex (dtp, len, dlen);
-              break;
+	    /* Same as for REAL, copy back to temp.  */
+	    read_complex (dtp, pdata, len, dlen);
+	    memcpy (dtp->u.p.value, pdata, dlen);
+	    break;
 
 	  case GFC_DTYPE_DERIVED:
 	    obj_name_len = strlen (nl->var_name) + 1;
diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c
index b651665..2ee7faa 100644
--- a/libgfortran/io/read.c
+++ b/libgfortran/io/read.c
@@ -131,8 +131,10 @@ max_value (int length, int signed_flag)
 
 /* convert_real()-- Convert a character representation of a floating
  * point number to the machine number.  Returns nonzero if there is a
- * range problem during conversion.  TODO: handle not-a-numbers and
- * infinities.  */
+ * range problem during conversion.  Note: many architectures
+ * (e.g. IA-64, HP-PA) require that the storage pointed to by the dest
+ * argument is properly aligned for the type in question.  TODO:
+ * handle not-a-numbers and infinities.  */
 
 int
 convert_real (st_parameter_dt *dtp, void *dest, const char *buffer, int length)

Attachment: signature.asc
Description: OpenPGP digital signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]