From 581d232670be67eb51d3839c43f1113507a89185 Mon Sep 17 00:00:00 2001 From: Janne Blomqvist Date: Thu, 13 Nov 2014 14:05:01 +0200 Subject: [PATCH] PR 60324 Unbounded stack allocations in libgfortran. 2014-11-13 Janne Blomqvist PR libfortran/60324 * configure: Regenerated. * configure.ac (AM_CFLAGS): Add Werror=vla. * libgfortran.h (gfc_alloca): Remove macro. (fc_strdup_notrim): New prototype. * intrinsics/access.c (access_func): Use fc_strdup rather than stack allocation. * intrinsics/chdir.c (chdir_i4_sub): Likewise. (chdir_i8_sub): Likewise. * intrinsics/chmod.c (chmod_internal): New function, move logic here. (chmod_func): Call chmod_internal. * intrinsics/env.c (getenv): Use fc_strdup rather than stack allocation. (get_environment_variable_i4): Likewise. * intrinsics/execute_command_line.c (execute_command_line): Likewise. * intrinsics/hostnm.c (hostnm_0): New function, use static buffer rather than VLA. (hostnm_i4_sub): Call hostnm_0. (hostnm_i8_sub): Likewise. (hostnm): Likewise. * intrinsics/link.c (link_internal): New function, use fc_strdup rather than stack allocation. (link_i4_sub): Call link_internal. (link_i8_sub): Likewise. (link_i4): Likewise. (link_i8): Likewise. * intrinsics/perror.c (perror_sub): Use fc_strdup rather than stack allocation. * intrinsics/random.c (random_seed_i4): Use static buffer rather than VLA, use _Static_assert to make sure it's big enough. * intrinsics/rename.c (rename_internal): New function, use fc_strdup rather than stack allocation. (rename_i4_sub): Call rename_internal. (rename_i8_sub): Likewise. (rename_i4): Likewise. (rename_i8): Likewise. * intrinsics/stat.c (stat_i4_sub_0): Use fc_strdup rather than stack allocation. (stat_i8_sub_0): Likewise. * intrinsics/symlink.c (symlnk_internal): New function, use fc_strdup rather than stack allocation. (symlnk_i4_sub): Call symlnk_internal. (symlnk_i8_sub): Likewise. (symlnk_i4): Likewise. (symlnk_i8): Likewise. * intrinsics/system.c (system_sub): Use fc_strdup rather than stack allocation. * intrinsics/unlink.c (unlink_i4_sub): Likewise. * io/file_pos.c (READ_CHUNK): Make it a macro rather than variable. * io/list_read.c (nml_get_obj_data): Use fixed stack buffer, fall back to xmalloc/free for large sizes. * io/read.c (read_f): Likewise. * io/transfer.c (MAX_READ): Make it a macro rather than variable. (WRITE_CHUNK): Likewise. * io/write_float.def (write_float): Use fixed stack buffer, fall back to xmalloc/free for large sizes. * runtime/string.c (fc_strdup_notrim): New function. From-SVN: r217480 --- libgfortran/ChangeLog | 62 +++++++++++++++ libgfortran/configure | 2 +- libgfortran/configure.ac | 2 +- libgfortran/intrinsics/access.c | 17 ++--- libgfortran/intrinsics/chdir.c | 24 +----- libgfortran/intrinsics/chmod.c | 31 ++++---- libgfortran/intrinsics/env.c | 30 +++----- libgfortran/intrinsics/execute_command_line.c | 6 +- libgfortran/intrinsics/hostnm.c | 56 +++++++------- libgfortran/intrinsics/link.c | 75 +++++++------------ libgfortran/intrinsics/perror.c | 13 +--- libgfortran/intrinsics/random.c | 6 +- libgfortran/intrinsics/rename.c | 70 ++++++----------- libgfortran/intrinsics/stat.c | 20 ++--- libgfortran/intrinsics/symlnk.c | 68 +++++------------ libgfortran/intrinsics/system.c | 6 +- libgfortran/intrinsics/unlink.c | 12 +-- libgfortran/io/file_pos.c | 2 +- libgfortran/io/list_read.c | 13 +++- libgfortran/io/read.c | 16 +++- libgfortran/io/transfer.c | 4 +- libgfortran/io/write_float.def | 10 ++- libgfortran/libgfortran.h | 7 +- libgfortran/runtime/string.c | 14 ++++ 24 files changed, 271 insertions(+), 295 deletions(-) diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 2d600d1947e..119e1aef402 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,65 @@ +2014-11-13 Janne Blomqvist + + PR libfortran/60324 + * configure: Regenerated. + * configure.ac (AM_CFLAGS): Add Werror=vla. + * libgfortran.h (gfc_alloca): Remove macro. + (fc_strdup_notrim): New prototype. + * intrinsics/access.c (access_func): Use fc_strdup rather than + stack allocation. + * intrinsics/chdir.c (chdir_i4_sub): Likewise. + (chdir_i8_sub): Likewise. + * intrinsics/chmod.c (chmod_internal): New function, move logic + here. + (chmod_func): Call chmod_internal. + * intrinsics/env.c (getenv): Use fc_strdup rather than stack + allocation. + (get_environment_variable_i4): Likewise. + * intrinsics/execute_command_line.c (execute_command_line): + Likewise. + * intrinsics/hostnm.c (hostnm_0): New function, use static buffer + rather than VLA. + (hostnm_i4_sub): Call hostnm_0. + (hostnm_i8_sub): Likewise. + (hostnm): Likewise. + * intrinsics/link.c (link_internal): New function, use fc_strdup + rather than stack allocation. + (link_i4_sub): Call link_internal. + (link_i8_sub): Likewise. + (link_i4): Likewise. + (link_i8): Likewise. + * intrinsics/perror.c (perror_sub): Use fc_strdup rather than + stack allocation. + * intrinsics/random.c (random_seed_i4): Use static buffer rather + than VLA, use _Static_assert to make sure it's big enough. + * intrinsics/rename.c (rename_internal): New function, use + fc_strdup rather than stack allocation. + (rename_i4_sub): Call rename_internal. + (rename_i8_sub): Likewise. + (rename_i4): Likewise. + (rename_i8): Likewise. + * intrinsics/stat.c (stat_i4_sub_0): Use fc_strdup rather than + stack allocation. + (stat_i8_sub_0): Likewise. + * intrinsics/symlink.c (symlnk_internal): New function, use + fc_strdup rather than stack allocation. + (symlnk_i4_sub): Call symlnk_internal. + (symlnk_i8_sub): Likewise. + (symlnk_i4): Likewise. + (symlnk_i8): Likewise. + * intrinsics/system.c (system_sub): Use fc_strdup rather than + stack allocation. + * intrinsics/unlink.c (unlink_i4_sub): Likewise. + * io/file_pos.c (READ_CHUNK): Make it a macro rather than variable. + * io/list_read.c (nml_get_obj_data): Use fixed stack buffer, fall + back to xmalloc/free for large sizes. + * io/read.c (read_f): Likewise. + * io/transfer.c (MAX_READ): Make it a macro rather than variable. + (WRITE_CHUNK): Likewise. + * io/write_float.def (write_float): Use fixed stack buffer, fall + back to xmalloc/free for large sizes. + * runtime/string.c (fc_strdup_notrim): New function. + 2014-11-11 Francois-Xavier Coudert PR target/63610 diff --git a/libgfortran/configure b/libgfortran/configure index e02ef1a7281..17d7570e26c 100755 --- a/libgfortran/configure +++ b/libgfortran/configure @@ -5783,7 +5783,7 @@ if test "x$GCC" = "xyes"; then ## We like to use C11 and C99 routines when available. This makes ## sure that ## __STDC_VERSION__ is set such that libc includes make them available. - AM_CFLAGS="-std=gnu11 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wextra -Wwrite-strings -Werror=implicit-function-declaration" + AM_CFLAGS="-std=gnu11 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wextra -Wwrite-strings -Werror=implicit-function-declaration -Werror=vla" ## Compile the following tests with the same system header contents ## that we'll encounter when compiling our own source files. CFLAGS="-std=gnu11 $CFLAGS" diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index f54104bb460..ada74e3318a 100644 --- a/libgfortran/configure.ac +++ b/libgfortran/configure.ac @@ -142,7 +142,7 @@ if test "x$GCC" = "xyes"; then ## We like to use C11 and C99 routines when available. This makes ## sure that ## __STDC_VERSION__ is set such that libc includes make them available. - AM_CFLAGS="-std=gnu11 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wextra -Wwrite-strings -Werror=implicit-function-declaration" + AM_CFLAGS="-std=gnu11 -Wall -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wextra -Wwrite-strings -Werror=implicit-function-declaration -Werror=vla" ## Compile the following tests with the same system header contents ## that we'll encounter when compiling our own source files. CFLAGS="-std=gnu11 $CFLAGS" diff --git a/libgfortran/intrinsics/access.c b/libgfortran/intrinsics/access.c index a418d6703c5..65a0a103e25 100644 --- a/libgfortran/intrinsics/access.c +++ b/libgfortran/intrinsics/access.c @@ -2,7 +2,7 @@ Copyright (C) 2006-2014 Free Software Foundation, Inc. Contributed by François-Xavier Coudert -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -43,7 +43,6 @@ int access_func (char *name, char *mode, gfc_charlen_type name_len, gfc_charlen_type mode_len) { - char * file; gfc_charlen_type i; int m; @@ -75,16 +74,12 @@ access_func (char *name, char *mode, gfc_charlen_type name_len, break; } - /* Trim trailing spaces from NAME argument. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - - /* Make a null terminated copy of the string. */ - file = gfc_alloca (name_len + 1); - memcpy (file, name, name_len); - file[name_len] = '\0'; + char *path = fc_strdup (name, name_len); /* And make the call to access(). */ - return (access (file, m) == 0 ? 0 : errno); + int res = (access (path, m) == 0 ? 0 : errno); + + free (path); + return res; } #endif diff --git a/libgfortran/intrinsics/chdir.c b/libgfortran/intrinsics/chdir.c index c4933a3d5f3..87419a82e3c 100644 --- a/libgfortran/intrinsics/chdir.c +++ b/libgfortran/intrinsics/chdir.c @@ -44,18 +44,10 @@ void chdir_i4_sub (char *dir, GFC_INTEGER_4 *status, gfc_charlen_type dir_len) { int val; - char *str; - - /* Trim trailing spaces from paths. */ - while (dir_len > 0 && dir[dir_len - 1] == ' ') - dir_len--; - - /* Make a null terminated copy of the strings. */ - str = gfc_alloca (dir_len + 1); - memcpy (str, dir, dir_len); - str[dir_len] = '\0'; + char *str = fc_strdup (dir, dir_len); val = chdir (str); + free (str); if (status != NULL) *status = (val == 0) ? 0 : errno; @@ -69,18 +61,10 @@ void chdir_i8_sub (char *dir, GFC_INTEGER_8 *status, gfc_charlen_type dir_len) { int val; - char *str; - - /* Trim trailing spaces from paths. */ - while (dir_len > 0 && dir[dir_len - 1] == ' ') - dir_len--; - - /* Make a null terminated copy of the strings. */ - str = gfc_alloca (dir_len + 1); - memcpy (str, dir, dir_len); - str[dir_len] = '\0'; + char *str = fc_strdup (dir, dir_len); val = chdir (str); + free (str); if (status != NULL) *status = (val == 0) ? 0 : errno; diff --git a/libgfortran/intrinsics/chmod.c b/libgfortran/intrinsics/chmod.c index acef433d92e..c42fa8c28fa 100644 --- a/libgfortran/intrinsics/chmod.c +++ b/libgfortran/intrinsics/chmod.c @@ -61,14 +61,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see A return value of 0 indicates success, -1 an error of chmod() while 1 indicates a mode parsing error. */ -extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type); -export_proto(chmod_func); -int -chmod_func (char *name, char *mode, gfc_charlen_type name_len, - gfc_charlen_type mode_len) +static int +chmod_internal (char *file, char *mode, gfc_charlen_type mode_len) { - char * file; int i; bool ugo[3]; bool rwxXstugo[9]; @@ -80,15 +76,6 @@ chmod_func (char *name, char *mode, gfc_charlen_type name_len, mode_t mode_mask, file_mode, new_mode; struct stat stat_buf; - /* Trim trailing spaces of the file name. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - - /* Make a null terminated copy of the file name. */ - file = gfc_alloca (name_len + 1); - memcpy (file, name, name_len); - file[name_len] = '\0'; - if (mode_len == 0) return 1; @@ -496,6 +483,20 @@ clause_done: } +extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type); +export_proto(chmod_func); + +int +chmod_func (char *name, char *mode, gfc_charlen_type name_len, + gfc_charlen_type mode_len) +{ + char *cname = fc_strdup (name, name_len); + int ret = chmod_internal (cname, mode, mode_len); + free (cname); + return ret; +} + + extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, gfc_charlen_type); export_proto(chmod_i4_sub); diff --git a/libgfortran/intrinsics/env.c b/libgfortran/intrinsics/env.c index 9f4507305cd..ffdc54ac42f 100644 --- a/libgfortran/intrinsics/env.c +++ b/libgfortran/intrinsics/env.c @@ -52,27 +52,19 @@ PREFIX(getenv) (char * name, char * value, gfc_charlen_type name_len, else memset (value, ' ', value_len); /* Blank the string. */ - /* Trim trailing spaces from name. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - /* Make a null terminated copy of the string. */ - name_nt = gfc_alloca (name_len + 1); - memcpy (name_nt, name, name_len); - name_nt[name_len] = '\0'; + name_nt = fc_strdup (name, name_len); res = getenv(name_nt); + free (name_nt); + /* If res is NULL, it means that the environment variable didn't exist, so just return. */ if (res == NULL) return; - res_len = strlen(res); - if (value_len < res_len) - memcpy (value, res, value_len); - else - memcpy (value, res, res_len); + cf_strcpy (value, value_len, res); } @@ -127,18 +119,14 @@ get_environment_variable_i4 (char *name, char *value, GFC_INTEGER_4 *length, } if ((!trim_name) || *trim_name) - { - /* Trim trailing spaces from name. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - } - /* Make a null terminated copy of the name. */ - name_nt = gfc_alloca (name_len + 1); - memcpy (name_nt, name, name_len); - name_nt[name_len] = '\0'; + name_nt = fc_strdup (name, name_len); + else + name_nt = fc_strdup_notrim (name, name_len); res = getenv(name_nt); + free (name_nt); + if (res == NULL) stat = GFC_NAME_DOES_NOT_EXIST; else diff --git a/libgfortran/intrinsics/execute_command_line.c b/libgfortran/intrinsics/execute_command_line.c index 19cc29b3c42..578b4e92658 100644 --- a/libgfortran/intrinsics/execute_command_line.c +++ b/libgfortran/intrinsics/execute_command_line.c @@ -61,9 +61,7 @@ execute_command_line (const char *command, bool wait, int *exitstat, gfc_charlen_type cmdmsg_len) { /* Transform the Fortran string to a C string. */ - char cmd[command_len + 1]; - memcpy (cmd, command, command_len); - cmd[command_len] = '\0'; + char *cmd = fc_strdup (command, command_len); /* Flush all I/O units before executing the command. */ flush_all_units(); @@ -110,6 +108,8 @@ execute_command_line (const char *command, bool wait, int *exitstat, } } + free (cmd); + /* Now copy back to the Fortran string if needed. */ if (cmdstat && *cmdstat > EXEC_NOERROR) { diff --git a/libgfortran/intrinsics/hostnm.c b/libgfortran/intrinsics/hostnm.c index 856625826e5..c94dd775329 100644 --- a/libgfortran/intrinsics/hostnm.c +++ b/libgfortran/intrinsics/hostnm.c @@ -2,7 +2,7 @@ Copyright (C) 2005-2014 Free Software Foundation, Inc. Contributed by François-Xavier Coudert -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -32,6 +32,12 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include #endif +#include + +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 255 +#endif + /* Windows32 version */ #if defined __MINGW32__ && !defined HAVE_GETHOSTNAME @@ -79,19 +85,17 @@ w32_gethostname (char *name, size_t len) INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ #ifdef HAVE_GETHOSTNAME -extern void hostnm_i4_sub (char *, GFC_INTEGER_4 *, gfc_charlen_type); -iexport_proto(hostnm_i4_sub); - -void -hostnm_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len) +static int +hostnm_0 (char *name, gfc_charlen_type name_len) { int val, i; - char *p; + char p[HOST_NAME_MAX + 1]; memset (name, ' ', name_len); - p = gfc_alloca (name_len + 1); - val = gethostname (p, name_len); + size_t reqlen = sizeof (p) > (size_t) name_len + 1 + ? (size_t) name_len + 1: sizeof (p); + val = gethostname (p, reqlen); if (val == 0) { @@ -100,8 +104,18 @@ hostnm_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len) name[i] = p[i]; } + return ((val == 0) ? 0 : errno); +} + +extern void hostnm_i4_sub (char *, GFC_INTEGER_4 *, gfc_charlen_type); +iexport_proto(hostnm_i4_sub); + +void +hostnm_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len) +{ + int val = hostnm_0 (name, name_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(hostnm_i4_sub); @@ -111,23 +125,9 @@ iexport_proto(hostnm_i8_sub); void hostnm_i8_sub (char *name, GFC_INTEGER_8 *status, gfc_charlen_type name_len) { - int val, i; - char *p; - - memset (name, ' ', name_len); - p = gfc_alloca (name_len + 1); - - val = gethostname (p, name_len); - - if (val == 0) - { - i = -1; - while (i < name_len && p[++i] != '\0') - name[i] = p[i]; - } - + int val = hostnm_0 (name, name_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(hostnm_i8_sub); @@ -137,8 +137,6 @@ export_proto(hostnm); GFC_INTEGER_4 hostnm (char *name, gfc_charlen_type name_len) { - GFC_INTEGER_4 val; - hostnm_i4_sub (name, &val, name_len); - return val; + return hostnm_0 (name, name_len); } #endif diff --git a/libgfortran/intrinsics/link.c b/libgfortran/intrinsics/link.c index 2018c628a00..c6084a1cc66 100644 --- a/libgfortran/intrinsics/link.c +++ b/libgfortran/intrinsics/link.c @@ -2,7 +2,7 @@ Copyright (C) 2005-2014 Free Software Foundation, Inc. Contributed by François-Xavier Coudert -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -37,36 +37,39 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ #ifdef HAVE_LINK -extern void link_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, - gfc_charlen_type); -iexport_proto(link_i4_sub); -void -link_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, - gfc_charlen_type path1_len, gfc_charlen_type path2_len) +static int +link_internal (char *path1, char *path2, gfc_charlen_type path1_len, + gfc_charlen_type path2_len) { int val; char *str1, *str2; - /* Trim trailing spaces from paths. */ - while (path1_len > 0 && path1[path1_len - 1] == ' ') - path1_len--; - while (path2_len > 0 && path2[path2_len - 1] == ' ') - path2_len--; - /* Make a null terminated copy of the strings. */ - str1 = gfc_alloca (path1_len + 1); - memcpy (str1, path1, path1_len); - str1[path1_len] = '\0'; - - str2 = gfc_alloca (path2_len + 1); - memcpy (str2, path2, path2_len); - str2[path2_len] = '\0'; + str1 = fc_strdup (path1, path1_len); + str2 = fc_strdup (path2, path2_len); val = link (str1, str2); + free (str1); + free (str2); + + return ((val == 0) ? 0 : errno); +} + + +extern void link_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, + gfc_charlen_type); +iexport_proto(link_i4_sub); + +void +link_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, + gfc_charlen_type path1_len, gfc_charlen_type path2_len) +{ + int val = link_internal (path1, path2, path1_len, path2_len); + if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(link_i4_sub); @@ -78,28 +81,10 @@ void link_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - int val; - char *str1, *str2; - - /* Trim trailing spaces from paths. */ - while (path1_len > 0 && path1[path1_len - 1] == ' ') - path1_len--; - while (path2_len > 0 && path2[path2_len - 1] == ' ') - path2_len--; - - /* Make a null terminated copy of the strings. */ - str1 = gfc_alloca (path1_len + 1); - memcpy (str1, path1, path1_len); - str1[path1_len] = '\0'; - - str2 = gfc_alloca (path2_len + 1); - memcpy (str2, path2, path2_len); - str2[path2_len] = '\0'; - - val = link (str1, str2); + int val = link_internal (path1, path2, path1_len, path2_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(link_i8_sub); @@ -111,9 +96,7 @@ GFC_INTEGER_4 link_i4 (char *path1, char *path2, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - GFC_INTEGER_4 val; - link_i4_sub (path1, path2, &val, path1_len, path2_len); - return val; + return link_internal (path1, path2, path1_len, path2_len); } extern GFC_INTEGER_8 link_i8 (char *, char *, gfc_charlen_type, @@ -124,8 +107,6 @@ GFC_INTEGER_8 link_i8 (char *path1, char *path2, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - GFC_INTEGER_8 val; - link_i8_sub (path1, path2, &val, path1_len, path2_len); - return val; + return link_internal (path1, path2, path1_len, path2_len); } #endif diff --git a/libgfortran/intrinsics/perror.c b/libgfortran/intrinsics/perror.c index 9a2851f5507..a8f09728706 100644 --- a/libgfortran/intrinsics/perror.c +++ b/libgfortran/intrinsics/perror.c @@ -37,17 +37,8 @@ iexport_proto(perror_sub); void perror_sub (char *string, gfc_charlen_type string_len) { - char * str; - - /* Trim trailing spaces from paths. */ - while (string_len > 0 && string[string_len - 1] == ' ') - string_len--; - - /* Make a null terminated copy of the strings. */ - str = gfc_alloca (string_len + 1); - memcpy (str, string, string_len); - str[string_len] = '\0'; - + char *str = fc_strdup (string, string_len); perror (str); + free (str); } iexport(perror_sub); diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/random.c index 593a6518cae..5e919292aab 100644 --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -666,7 +666,11 @@ void random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) { int i; - unsigned char seed[4*kiss_size]; + +#define KISS_MAX_SIZE 12 + unsigned char seed[4 * KISS_MAX_SIZE]; + _Static_assert (kiss_size <= KISS_MAX_SIZE, + "kiss_size must <= KISS_MAX_SIZE"); __gthread_mutex_lock (&random_lock); diff --git a/libgfortran/intrinsics/rename.c b/libgfortran/intrinsics/rename.c index 63901df4398..aabf8211c70 100644 --- a/libgfortran/intrinsics/rename.c +++ b/libgfortran/intrinsics/rename.c @@ -2,7 +2,7 @@ Copyright (C) 2005-2014 Free Software Foundation, Inc. Contributed by François-Xavier Coudert -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -28,6 +28,20 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include #include + +static int +rename_internal (char *path1, char *path2, gfc_charlen_type path1_len, + gfc_charlen_type path2_len) +{ + char *str1 = fc_strdup (path1, path1_len); + char *str2 = fc_strdup (path2, path2_len); + int val = rename (str1, str2); + free (str1); + free (str2); + return ((val == 0) ? 0 : errno); +} + + /* SUBROUTINE RENAME(PATH1, PATH2, STATUS) CHARACTER(len=*), INTENT(IN) :: PATH1, PATH2 INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ @@ -40,28 +54,9 @@ void rename_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - int val; - char *str1, *str2; - - /* Trim trailing spaces from paths. */ - while (path1_len > 0 && path1[path1_len - 1] == ' ') - path1_len--; - while (path2_len > 0 && path2[path2_len - 1] == ' ') - path2_len--; - - /* Make a null terminated copy of the strings. */ - str1 = gfc_alloca (path1_len + 1); - memcpy (str1, path1, path1_len); - str1[path1_len] = '\0'; - - str2 = gfc_alloca (path2_len + 1); - memcpy (str2, path2, path2_len); - str2[path2_len] = '\0'; - - val = rename (str1, str2); - + int val = rename_internal (path1, path2, path1_len, path2_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(rename_i4_sub); @@ -73,28 +68,9 @@ void rename_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - int val; - char *str1, *str2; - - /* Trim trailing spaces from paths. */ - while (path1_len > 0 && path1[path1_len - 1] == ' ') - path1_len--; - while (path2_len > 0 && path2[path2_len - 1] == ' ') - path2_len--; - - /* Make a null terminated copy of the strings. */ - str1 = gfc_alloca (path1_len + 1); - memcpy (str1, path1, path1_len); - str1[path1_len] = '\0'; - - str2 = gfc_alloca (path2_len + 1); - memcpy (str2, path2, path2_len); - str2[path2_len] = '\0'; - - val = rename (str1, str2); - + int val = rename_internal (path1, path2, path1_len, path2_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(rename_i8_sub); @@ -106,9 +82,7 @@ GFC_INTEGER_4 rename_i4 (char *path1, char *path2, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - GFC_INTEGER_4 val; - rename_i4_sub (path1, path2, &val, path1_len, path2_len); - return val; + return rename_internal (path1, path2, path1_len, path2_len); } extern GFC_INTEGER_8 rename_i8 (char *, char *, gfc_charlen_type, @@ -119,7 +93,5 @@ GFC_INTEGER_8 rename_i8 (char *path1, char *path2, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - GFC_INTEGER_8 val; - rename_i8_sub (path1, path2, &val, path1_len, path2_len); - return val; + return rename_internal (path1, path2, path1_len, path2_len); } diff --git a/libgfortran/intrinsics/stat.c b/libgfortran/intrinsics/stat.c index 1bd8b4b5a71..a60664210ec 100644 --- a/libgfortran/intrinsics/stat.c +++ b/libgfortran/intrinsics/stat.c @@ -67,14 +67,8 @@ stat_i4_sub_0 (char *name, gfc_array_i4 *sarray, GFC_INTEGER_4 *status, if (GFC_DESCRIPTOR_EXTENT(sarray,0) < 13) runtime_error ("Array size of SARRAY is too small."); - /* Trim trailing spaces from name. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - /* Make a null terminated copy of the string. */ - str = gfc_alloca (name_len + 1); - memcpy (str, name, name_len); - str[name_len] = '\0'; + str = fc_strdup (name, name_len); /* On platforms that don't provide lstat(), we use stat() instead. */ #ifdef HAVE_LSTAT @@ -84,6 +78,8 @@ stat_i4_sub_0 (char *name, gfc_array_i4 *sarray, GFC_INTEGER_4 *status, #endif val = stat(str, &sb); + free (str); + if (val == 0) { index_type stride = GFC_DESCRIPTOR_STRIDE(sarray,0); @@ -188,14 +184,8 @@ stat_i8_sub_0 (char *name, gfc_array_i8 *sarray, GFC_INTEGER_8 *status, if (GFC_DESCRIPTOR_EXTENT(sarray,0) < 13) runtime_error ("Array size of SARRAY is too small."); - /* Trim trailing spaces from name. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - /* Make a null terminated copy of the string. */ - str = gfc_alloca (name_len + 1); - memcpy (str, name, name_len); - str[name_len] = '\0'; + str = fc_strdup (name, name_len); /* On platforms that don't provide lstat(), we use stat() instead. */ #ifdef HAVE_LSTAT @@ -205,6 +195,8 @@ stat_i8_sub_0 (char *name, gfc_array_i8 *sarray, GFC_INTEGER_8 *status, #endif val = stat(str, &sb); + free (str); + if (val == 0) { index_type stride = GFC_DESCRIPTOR_STRIDE(sarray,0); diff --git a/libgfortran/intrinsics/symlnk.c b/libgfortran/intrinsics/symlnk.c index 3c3d2fbba79..5c53cb75378 100644 --- a/libgfortran/intrinsics/symlnk.c +++ b/libgfortran/intrinsics/symlnk.c @@ -2,7 +2,7 @@ Copyright (C) 2005-2014 Free Software Foundation, Inc. Contributed by François-Xavier Coudert -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -37,6 +37,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ #ifdef HAVE_SYMLINK +static int +symlnk_internal (char *path1, char *path2, gfc_charlen_type path1_len, + gfc_charlen_type path2_len) +{ + char *str1 = fc_strdup (path1, path1_len); + char *str2 = fc_strdup (path2, path2_len); + int val = symlink (str1, str2); + free (str1); + free (str2); + return ((val == 0) ? 0 : errno); +} + extern void symlnk_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, gfc_charlen_type); iexport_proto(symlnk_i4_sub); @@ -45,28 +57,9 @@ void symlnk_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - int val; - char *str1, *str2; - - /* Trim trailing spaces from paths. */ - while (path1_len > 0 && path1[path1_len - 1] == ' ') - path1_len--; - while (path2_len > 0 && path2[path2_len - 1] == ' ') - path2_len--; - - /* Make a null terminated copy of the strings. */ - str1 = gfc_alloca (path1_len + 1); - memcpy (str1, path1, path1_len); - str1[path1_len] = '\0'; - - str2 = gfc_alloca (path2_len + 1); - memcpy (str2, path2, path2_len); - str2[path2_len] = '\0'; - - val = symlink (str1, str2); - + int val = symlnk_internal (path1, path2, path1_len, path2_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(symlnk_i4_sub); @@ -78,28 +71,9 @@ void symlnk_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - int val; - char *str1, *str2; - - /* Trim trailing spaces from paths. */ - while (path1_len > 0 && path1[path1_len - 1] == ' ') - path1_len--; - while (path2_len > 0 && path2[path2_len - 1] == ' ') - path2_len--; - - /* Make a null terminated copy of the strings. */ - str1 = gfc_alloca (path1_len + 1); - memcpy (str1, path1, path1_len); - str1[path1_len] = '\0'; - - str2 = gfc_alloca (path2_len + 1); - memcpy (str2, path2, path2_len); - str2[path2_len] = '\0'; - - val = symlink (str1, str2); - + int val = symlnk_internal (path1, path2, path1_len, path2_len); if (status != NULL) - *status = (val == 0) ? 0 : errno; + *status = val; } iexport(symlnk_i8_sub); @@ -111,9 +85,7 @@ GFC_INTEGER_4 symlnk_i4 (char *path1, char *path2, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - GFC_INTEGER_4 val; - symlnk_i4_sub (path1, path2, &val, path1_len, path2_len); - return val; + return symlnk_internal (path1, path2, path1_len, path2_len); } extern GFC_INTEGER_8 symlnk_i8 (char *, char *, gfc_charlen_type, @@ -124,8 +96,6 @@ GFC_INTEGER_8 symlnk_i8 (char *path1, char *path2, gfc_charlen_type path1_len, gfc_charlen_type path2_len) { - GFC_INTEGER_8 val; - symlnk_i8_sub (path1, path2, &val, path1_len, path2_len); - return val; + return symlnk_internal (path1, path2, path1_len, path2_len); } #endif diff --git a/libgfortran/intrinsics/system.c b/libgfortran/intrinsics/system.c index d0a131d60e1..add6f4ff218 100644 --- a/libgfortran/intrinsics/system.c +++ b/libgfortran/intrinsics/system.c @@ -34,16 +34,14 @@ iexport_proto(system_sub); void system_sub (const char *fcmd, GFC_INTEGER_4 *status, gfc_charlen_type cmd_len) { - char cmd[cmd_len + 1]; + char *cmd = fc_strdup (fcmd, cmd_len); int stat; /* Flush all I/O units before executing the command. */ flush_all_units(); - memcpy (cmd, fcmd, cmd_len); - cmd[cmd_len] = '\0'; - stat = system (cmd); + free (cmd); if (status) *status = stat; } diff --git a/libgfortran/intrinsics/unlink.c b/libgfortran/intrinsics/unlink.c index b4de6e65cbe..2971a62e7e0 100644 --- a/libgfortran/intrinsics/unlink.c +++ b/libgfortran/intrinsics/unlink.c @@ -2,7 +2,7 @@ Copyright (C) 2004-2014 Free Software Foundation, Inc. Contributed by Steven G. Kargl . -This file is part of the GNU Fortran 95 runtime library (libgfortran). +This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public @@ -46,17 +46,13 @@ unlink_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len) char *str; GFC_INTEGER_4 stat; - /* Trim trailing spaces from name. */ - while (name_len > 0 && name[name_len - 1] == ' ') - name_len--; - /* Make a null terminated copy of the string. */ - str = gfc_alloca (name_len + 1); - memcpy (str, name, name_len); - str[name_len] = '\0'; + str = fc_strdup (name, name_len); stat = unlink (str); + free (str); + if (status != NULL) *status = (stat == 0) ? stat : errno; } diff --git a/libgfortran/io/file_pos.c b/libgfortran/io/file_pos.c index 85183a6632d..061f42ea9be 100644 --- a/libgfortran/io/file_pos.c +++ b/libgfortran/io/file_pos.c @@ -36,7 +36,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see record, and we have to sift backwards to find the newline before that or the start of the file, whichever comes first. */ -static const int READ_CHUNK = 4096; +#define READ_CHUNK 4096 static void formatted_backspace (st_parameter_filepos *fpp, gfc_unit *u) diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c index 1cb329f7df4..20b2b83a5e6 100644 --- a/libgfortran/io/list_read.c +++ b/libgfortran/io/list_read.c @@ -3132,16 +3132,27 @@ get_name: if (component_flag) { +#define EXT_STACK_SZ 100 + char ext_stack[EXT_STACK_SZ]; + char *ext_name; size_t var_len = strlen (root_nl->var_name); size_t saved_len = dtp->u.p.saved_string ? strlen (dtp->u.p.saved_string) : 0; - char ext_name[var_len + saved_len + 1]; + size_t ext_size = var_len + saved_len + 1; + + if (ext_size > EXT_STACK_SZ) + ext_name = xmalloc (ext_size); + else + ext_name = ext_stack; memcpy (ext_name, root_nl->var_name, var_len); if (dtp->u.p.saved_string) memcpy (ext_name + var_len, dtp->u.p.saved_string, saved_len); ext_name[var_len + saved_len] = '\0'; nl = find_nml_node (dtp, ext_name); + + if (ext_size > EXT_STACK_SZ) + free (ext_name); } else nl = find_nml_node (dtp, dtp->u.p.saved_string); diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c index 64f2ddf49a1..5c56dc26e42 100644 --- a/libgfortran/io/read.c +++ b/libgfortran/io/read.c @@ -881,6 +881,9 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length, void read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length) { +#define READF_TMP 50 + char tmp[READF_TMP]; + size_t buf_size = 0; int w, seen_dp, exponent; int exponent_sign; const char *p; @@ -895,6 +898,7 @@ read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length) exponent_sign = 1; exponent = 0; w = f->u.w; + buffer = tmp; /* Read in the next block. */ p = read_block_form (dtp, &w); @@ -911,7 +915,10 @@ read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length) exponent because of an implicit decimal point or the like. Thus allocating strlen ("+0.0e-1000") == 10 characters plus one for NUL more than the original buffer had should be enough. */ - buffer = gfc_alloca (w + 11); + buf_size = w + 11; + if (buf_size > READF_TMP) + buffer = xmalloc (buf_size); + out = buffer; /* Optional sign */ @@ -984,6 +991,8 @@ read_f (st_parameter_dt *dtp, const fnode *f, char *dest, int length) goto bad_float; convert_infnan (dtp, dest, buffer, length); + if (buf_size > READF_TMP) + free (buffer); return; } @@ -1170,7 +1179,8 @@ done: /* Do the actual conversion. */ convert_real (dtp, dest, buffer, length); - + if (buf_size > READF_TMP) + free (buffer); return; /* The value read is zero. */ @@ -1203,6 +1213,8 @@ zero: return; bad_float: + if (buf_size > READF_TMP) + free (buffer); generate_error (&dtp->common, LIBERROR_READ_VALUE, "Bad value during floating point read"); next_record (dtp, 1); diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c index 87b8c05c1a4..71c60b6f412 100644 --- a/libgfortran/io/transfer.c +++ b/libgfortran/io/transfer.c @@ -2982,7 +2982,7 @@ static void skip_record (st_parameter_dt *dtp, ssize_t bytes) { ssize_t rlength, readb; - static const ssize_t MAX_READ = 4096; +#define MAX_READ 4096 char p[MAX_READ]; dtp->u.p.current_unit->bytes_left_subrecord += bytes; @@ -3282,7 +3282,7 @@ next_record_w_unf (st_parameter_dt *dtp, int next_subrecord) static ssize_t sset (stream * s, int c, ssize_t nbyte) { - static const int WRITE_CHUNK = 256; +#define WRITE_CHUNK 256 char p[WRITE_CHUNK]; ssize_t bytes_left, trans; diff --git a/libgfortran/io/write_float.def b/libgfortran/io/write_float.def index 99f6ff8e83f..1b345f8fc4b 100644 --- a/libgfortran/io/write_float.def +++ b/libgfortran/io/write_float.def @@ -1277,7 +1277,13 @@ write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \ trailing null, and finally some extra digits depending on the requested precision. */ const size_t size = 4932 + 3 + precision; - char buffer[size]; +#define BUF_STACK_SZ 5000 + char buf_stack[BUF_STACK_SZ]; + char *buffer; + if (size > BUF_STACK_SZ) + buffer = xmalloc (size); + else + buffer = buf_stack; switch (len) { @@ -1306,4 +1312,6 @@ write_float (st_parameter_dt *dtp, const fnode *f, const char *source, \ default: internal_error (NULL, "bad real kind"); } + if (size > BUF_STACK_SZ) + free (buffer); } diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index d2de76fcb92..bf7442c405a 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -573,10 +573,6 @@ iexport_data_proto(line); extern char *filename; iexport_data_proto(filename); -/* Avoid conflicting prototypes of alloca() in system headers by using - GCC's builtin alloca(). */ -#define gfc_alloca(x) __builtin_alloca(x) - /* The default value of record length for preconnected units is defined here. This value can be overriden by an environment variable. @@ -851,6 +847,9 @@ export_proto(string_len_trim_char4); extern char *fc_strdup(const char *, gfc_charlen_type); internal_proto(fc_strdup); +extern char *fc_strdup_notrim(const char *, gfc_charlen_type); +internal_proto(fc_strdup_notrim); + /* io/intrinsics.c */ extern void flush_all_units (void); diff --git a/libgfortran/runtime/string.c b/libgfortran/runtime/string.c index b95d1997a5c..79f75b44458 100644 --- a/libgfortran/runtime/string.c +++ b/libgfortran/runtime/string.c @@ -134,6 +134,20 @@ fc_strdup (const char *src, gfc_charlen_type src_len) } +/* Duplicate a non-null-terminated Fortran string to a malloced + null-terminated C string, without getting rid of trailing + blanks. */ + +char * +fc_strdup_notrim (const char *src, gfc_charlen_type src_len) +{ + char *p = strndup (src, src_len); + if (!p) + os_error ("Memory allocation failed in fc_strdup"); + return p; +} + + /* Given a fortran string and an array of st_option structures, search through the array to find a match. If the option is not found, we generate an error if no default is provided. */ -- 2.30.2