summaryrefslogtreecommitdiff
path: root/libgfortran
diff options
context:
space:
mode:
authorjvdelisle <jvdelisle@138bc75d-0d04-0410-961f-82ee72b054a4>2015-04-15 01:27:03 +0000
committerjvdelisle <jvdelisle@138bc75d-0d04-0410-961f-82ee72b054a4>2015-04-15 01:27:03 +0000
commit7502b19d938bde2fcfc9d5976e82003349dce04f (patch)
tree069058137168dad71c78507962553db85245d69c /libgfortran
parent01f8008f681cce2efc5a5cd3eddb5ee0bab46eb1 (diff)
downloadgcc-7502b19d938bde2fcfc9d5976e82003349dce04f.tar.gz
2015-04-14 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/65089 * io/format.h (free_format): New function to free memory allocated for building format error messages. * io/format.c (format_error): Add checks before freeing memory to avoid potential segfaults and free formatting data when needed on error conditions. Always allocate and NULL terminate the string. * io/transfer.c (st_read_done, st_write_done): Use new free_format function to clean up memory allocations when done. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@222111 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgfortran')
-rw-r--r--libgfortran/ChangeLog12
-rw-r--r--libgfortran/io/format.c56
-rw-r--r--libgfortran/io/format.h3
-rw-r--r--libgfortran/io/transfer.c15
4 files changed, 67 insertions, 19 deletions
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 67bb9cce5e1..9f53ae3e8af 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,15 @@
+2015-04-14 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR libgfortran/65089
+ * io/format.h (free_format): New function to free memory
+ allocated for building format error messages.
+ * io/format.c (format_error): Add checks before freeing memory
+ to avoid potential segfaults and free formatting data when
+ needed on error conditions. Always allocate and NULL terminate
+ the string.
+ * io/transfer.c (st_read_done, st_write_done): Use new
+ free_format function to clean up memory allocations when done.
+
2015-03-28 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/65596
diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c
index fa81d9b87fc..42be2586e1f 100644
--- a/libgfortran/io/format.c
+++ b/libgfortran/io/format.c
@@ -243,6 +243,18 @@ get_fnode (format_data *fmt, fnode **head, fnode **tail, format_token t)
}
+/* free_format()-- Free allocated format string. */
+void
+free_format (st_parameter_dt *dtp)
+{
+ if ((dtp->common.flags & IOPARM_DT_HAS_FORMAT) && dtp->format)
+ {
+ free (dtp->format);
+ dtp->format = NULL;
+ }
+}
+
+
/* free_format_data()-- Free all allocated format data. */
void
@@ -1145,7 +1157,8 @@ format_error (st_parameter_dt *dtp, const fnode *f, const char *message)
p = strchr (buffer, '\0');
- memcpy (p, dtp->format, width);
+ if (dtp->format)
+ memcpy (p, dtp->format, width);
p += width;
*p++ = '\n';
@@ -1158,6 +1171,26 @@ format_error (st_parameter_dt *dtp, const fnode *f, const char *message)
*p++ = '^';
*p = '\0';
+ /* Cleanup any left over memory allocations before calling generate
+ error. */
+ if (is_internal_unit (dtp))
+ {
+ if (dtp->format != NULL)
+ {
+ free (dtp->format);
+ dtp->format = NULL;
+ }
+
+ /* Leave these alone if IOSTAT was given because execution will
+ return from generate error in those cases. */
+ if (!(dtp->common.flags & IOPARM_HAS_IOSTAT))
+ {
+ free (dtp->u.p.fmt);
+ free_format_hash_table (dtp->u.p.current_unit);
+ free_internal_unit (dtp);
+ }
+ }
+
generate_error (&dtp->common, LIBERROR_FORMAT, buffer);
}
@@ -1218,13 +1251,8 @@ parse_format (st_parameter_dt *dtp)
/* Not found so proceed as follows. */
- if (format_cache_ok)
- {
- char *fmt_string = xmalloc (dtp->format_len + 1);
- memcpy (fmt_string, dtp->format, dtp->format_len);
- dtp->format = fmt_string;
- dtp->format[dtp->format_len] = '\0';
- }
+ char *fmt_string = fc_strdup_notrim (dtp->format, dtp->format_len);
+ dtp->format = fmt_string;
dtp->u.p.fmt = fmt = xmalloc (sizeof (format_data));
fmt->format_string = dtp->format;
@@ -1256,19 +1284,13 @@ parse_format (st_parameter_dt *dtp)
else
fmt->error = "Missing initial left parenthesis in format";
- if (fmt->error)
- {
- format_error (dtp, NULL, fmt->error);
- if (format_cache_ok)
- free (dtp->format);
- free_format_hash_table (dtp->u.p.current_unit);
- return;
- }
-
if (format_cache_ok)
save_parsed_format (dtp);
else
dtp->u.p.format_not_saved = 1;
+
+ if (fmt->error)
+ format_error (dtp, NULL, fmt->error);
}
diff --git a/libgfortran/io/format.h b/libgfortran/io/format.h
index de5cdf9ee81..11319f468d4 100644
--- a/libgfortran/io/format.h
+++ b/libgfortran/io/format.h
@@ -132,6 +132,9 @@ internal_proto(format_error);
extern void free_format_data (struct format_data *);
internal_proto(free_format_data);
+extern void free_format (st_parameter_dt *);
+internal_proto(free_format);
+
extern void free_format_hash_table (gfc_unit *);
internal_proto(free_format_hash_table);
diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c
index 7bbee2131dd..746bb6dcc6c 100644
--- a/libgfortran/io/transfer.c
+++ b/libgfortran/io/transfer.c
@@ -3711,9 +3711,15 @@ void
st_read_done (st_parameter_dt *dtp)
{
finalize_transfer (dtp);
+
if (is_internal_unit (dtp) || dtp->u.p.format_not_saved)
- free_format_data (dtp->u.p.fmt);
+ {
+ free_format_data (dtp->u.p.fmt);
+ free_format (dtp);
+ }
+
free_ionml (dtp);
+
if (dtp->u.p.current_unit != NULL)
unlock_unit (dtp->u.p.current_unit);
@@ -3764,8 +3770,13 @@ st_write_done (st_parameter_dt *dtp)
}
if (is_internal_unit (dtp) || dtp->u.p.format_not_saved)
- free_format_data (dtp->u.p.fmt);
+ {
+ free_format_data (dtp->u.p.fmt);
+ free_format (dtp);
+ }
+
free_ionml (dtp);
+
if (dtp->u.p.current_unit != NULL)
unlock_unit (dtp->u.p.current_unit);