diff options
author | Jerry DeLisle <jvdelisle@gcc.gnu.org> | 2015-04-15 01:27:03 +0000 |
---|---|---|
committer | Jerry DeLisle <jvdelisle@gcc.gnu.org> | 2015-04-15 01:27:03 +0000 |
commit | 241cbc7a5f4b39f57c350e8fc32d3a43999ba63b (patch) | |
tree | 069058137168dad71c78507962553db85245d69c /libgfortran/io | |
parent | 182d115c19b636d1c33ebb905029853fc68e99da (diff) | |
download | gcc-241cbc7a5f4b39f57c350e8fc32d3a43999ba63b.zip gcc-241cbc7a5f4b39f57c350e8fc32d3a43999ba63b.tar.gz gcc-241cbc7a5f4b39f57c350e8fc32d3a43999ba63b.tar.bz2 |
re PR fortran/65089 (FAIL: gfortran.dg/io_real_boz(2|_[45]).f90 when tested with -fsanitize=address)
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.
From-SVN: r222111
Diffstat (limited to 'libgfortran/io')
-rw-r--r-- | libgfortran/io/format.c | 56 | ||||
-rw-r--r-- | libgfortran/io/format.h | 3 | ||||
-rw-r--r-- | libgfortran/io/transfer.c | 15 |
3 files changed, 55 insertions, 19 deletions
diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c index fa81d9b..42be258 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 de5cdf9..11319f4 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 7bbee21..746bb6d 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); |