Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On Sat, Nov 15, 2014 at 8:01 AM, Janne Blomqvist blomqvist.ja...@gmail.com wrote: On Fri, Nov 14, 2014 at 11:02 PM, Tobias Burnus bur...@net-b.de wrote: I think instead of doing a run-time check I'd prefer something like the following, keeping the compile-time assert. --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -253 +253 @@ static GFC_UINTEGER_4 kiss_default_seed[] = { -static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); +#define KISS_SIZE ((GFC_INTEGER_4) (sizeof(kiss_seed)/sizeof(kiss_seed[0])) (plus s/kiss_size/KISS_SIZE/ changes in the code.) Janne, what do you think? I like it. With this, you can also get rid of the assert and the newly introduced KISS_MAX_SIZE macro, and just make the seed array the correct size, as was originally done (with a VLA). Consider such a patch pre-approved. I went ahead and did it myself, committed the attached patch as r217623 after regtesting. 2014-11-16 Janne Blomqvist j...@gcc.gnu.org PR libfortran/60324 * intrinsics/random.c (kiss_size): Rename to KISS_SIZE, make it a macro instead of a variable. (random_seed_i4): Make seed correct size, remove assert, KISS_SIZE related changes. (random_seed_i8): KISS_SIZE related changes. -- Janne Blomqvist diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/random.c index 5e91929..d2510b2 100644 --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -224,7 +224,7 @@ KISS algorithm. */ z=0,c=0 and z=2^32-1,c=698769068 should be avoided. */ -/* Any modifications to the seeds that change kiss_size below need to be +/* Any modifications to the seeds that change KISS_SIZE below need to be reflected in check.c (gfc_check_random_seed) to enable correct compile-time checking of PUT size for the RANDOM_SEED intrinsic. */ @@ -250,7 +250,7 @@ static GFC_UINTEGER_4 kiss_default_seed[] = { #endif }; -static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); +#define KISS_SIZE (sizeof(kiss_seed)/sizeof(kiss_seed[0])) static GFC_UINTEGER_4 * const kiss_seed_1 = kiss_seed; static GFC_UINTEGER_4 * const kiss_seed_2 = kiss_seed + 4; @@ -665,12 +665,7 @@ unscramble_seed (unsigned char *dest, unsigned char *src, int size) void random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) { - int i; - -#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); + unsigned char seed[4 * KISS_SIZE]; __gthread_mutex_lock (random_lock); @@ -681,11 +676,11 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) /* From the standard: If no argument is present, the processor assigns a processor-dependent value to the seed. */ if (size == NULL put == NULL get == NULL) - for (i = 0; i kiss_size; i++) + for (size_t i = 0; i KISS_SIZE; i++) kiss_seed[i] = kiss_default_seed[i]; if (size != NULL) -*size = kiss_size; +*size = KISS_SIZE; if (put != NULL) { @@ -694,18 +689,18 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) runtime_error (Array rank of PUT is not 1.); /* If the array is too small, abort. */ - if (GFC_DESCRIPTOR_EXTENT(put,0) kiss_size) + if (GFC_DESCRIPTOR_EXTENT(put,0) (index_type) KISS_SIZE) runtime_error (Array size of PUT is too small.); /* We copy the seed given by the user. */ - for (i = 0; i kiss_size; i++) + for (size_t i = 0; i KISS_SIZE; i++) memcpy (seed + i * sizeof(GFC_UINTEGER_4), - (put-base_addr[(kiss_size - 1 - i) * GFC_DESCRIPTOR_STRIDE(put,0)]), + (put-base_addr[(KISS_SIZE - 1 - i) * GFC_DESCRIPTOR_STRIDE(put,0)]), sizeof(GFC_UINTEGER_4)); /* We put it after scrambling the bytes, to paper around users who provide seeds with quality only in the lower or upper part. */ - scramble_seed ((unsigned char *) kiss_seed, seed, 4*kiss_size); + scramble_seed ((unsigned char *) kiss_seed, seed, 4 * KISS_SIZE); } /* Return the seed to GET data. */ @@ -716,15 +711,15 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) runtime_error (Array rank of GET is not 1.); /* If the array is too small, abort. */ - if (GFC_DESCRIPTOR_EXTENT(get,0) kiss_size) + if (GFC_DESCRIPTOR_EXTENT(get,0) (index_type) KISS_SIZE) runtime_error (Array size of GET is too small.); /* Unscramble the seed. */ - unscramble_seed (seed, (unsigned char *) kiss_seed, 4*kiss_size); + unscramble_seed (seed, (unsigned char *) kiss_seed, 4 * KISS_SIZE); /* Then copy it back to the user variable. */ - for (i = 0; i kiss_size; i++) - memcpy ((get-base_addr[(kiss_size - 1 - i) *
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On 11/13/2014 02:32 AM, Janne Blomqvist wrote: in the spirit of PR 60324 and 61035, here's a patch that gets rid of the remaining potentially unbounded stack allocations in libgfortran. All uses of __builtin_alloca() and VLA's are replaced either straight with heap allocated memory, or with a fixed size stack buffer, potentially switching to heap storage for large sizes in places where performance might matter. In order to avoid reintroducing these kinds of issues, I also added -Werror=vla to AM_CFLAGS. This might also help limited targets like nvptx that lack VLA's. Regtested on x86_64-unknown-linux-gnu, Ok for trunk? I hit an error when building intrinsics/random.c: error: expression in static assertion is not constant Joseph told me that static const variables cannot be used in constant expressions in C, so I've replaced the _Static_assert with a regular assert. Are you using g++ to build libgfortran? I don't have a good baseline test this patch thoroughly, but at least I can bootstrap gcc without it failing in libgfortran. Is this OK for mainline and/or could someone see if it causes any regressions? Thanks, Cesar 2014-11-14 Cesar Philippidis ce...@codesourcery.com libgfortran/ * intrinsics/random.c (random_seed_i4): Replace _Static_assert with assert. diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/random.c index 5e91929..6b07a66d 100644 --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -25,6 +25,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see http://www.gnu.org/licenses/. */ #include libgfortran.h +#include assert.h #include gthr.h #include string.h @@ -669,8 +670,8 @@ random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) #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); + assert (kiss_size = KISS_MAX_SIZE + kiss_size must = KISS_MAX_SIZE); __gthread_mutex_lock (random_lock);
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
Cesar Philippidis wrote: On 11/13/2014 02:32 AM, Janne Blomqvist wrote: I hit an error when building intrinsics/random.c: error: expression in static assertion is not constant Joseph told me that static const variables cannot be used in constant expressions in C, so I've replaced the _Static_assert with a regular assert. Are you using g++ to build libgfortran? I wonder why you are seeing this while others aren't. It seemed to work for me, gcc-testresults looks fine and there weren't complaints yesterday or today. (The patch was committed 34 h ago.) The default build should use gcc and not g++. I don't have a good baseline test this patch thoroughly, but at least I can bootstrap gcc without it failing in libgfortran. Is this OK for mainline and/or could someone see if it causes any regressions? I think instead of doing a run-time check I'd prefer something like the following, keeping the compile-time assert. --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -253 +253 @@ static GFC_UINTEGER_4 kiss_default_seed[] = { -static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); +#define KISS_SIZE ((GFC_INTEGER_4) (sizeof(kiss_seed)/sizeof(kiss_seed[0])) (plus s/kiss_size/KISS_SIZE/ changes in the code.) Janne, what do you think? Tobias
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On Fri, Nov 14, 2014 at 11:02 PM, Tobias Burnus bur...@net-b.de wrote: Cesar Philippidis wrote: On 11/13/2014 02:32 AM, Janne Blomqvist wrote: I hit an error when building intrinsics/random.c: error: expression in static assertion is not constant Joseph told me that static const variables cannot be used in constant expressions in C, so I've replaced the _Static_assert with a regular assert. Are you using g++ to build libgfortran? I wonder why you are seeing this while others aren't. Yeah, I wonder the same? I don't have a good baseline test this patch thoroughly, but at least I can bootstrap gcc without it failing in libgfortran. Is this OK for mainline and/or could someone see if it causes any regressions? I think instead of doing a run-time check I'd prefer something like the following, keeping the compile-time assert. --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -253 +253 @@ static GFC_UINTEGER_4 kiss_default_seed[] = { -static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); +#define KISS_SIZE ((GFC_INTEGER_4) (sizeof(kiss_seed)/sizeof(kiss_seed[0])) (plus s/kiss_size/KISS_SIZE/ changes in the code.) Janne, what do you think? I like it. With this, you can also get rid of the assert and the newly introduced KISS_MAX_SIZE macro, and just make the seed array the correct size, as was originally done (with a VLA). Consider such a patch pre-approved. -- Janne Blomqvist
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On 11/14/2014 10:01 PM, Janne Blomqvist wrote: On Fri, Nov 14, 2014 at 11:02 PM, Tobias Burnus bur...@net-b.de wrote: Cesar Philippidis wrote: On 11/13/2014 02:32 AM, Janne Blomqvist wrote: I hit an error when building intrinsics/random.c: error: expression in static assertion is not constant Joseph told me that static const variables cannot be used in constant expressions in C, so I've replaced the _Static_assert with a regular assert. Are you using g++ to build libgfortran? I wonder why you are seeing this while others aren't. Yeah, I wonder the same? It does seem strange. Maybe that function isn't necessary for all targets? I've attached a reduced test case if anyone is interested in it. That error should show up with gcc random.c. I don't have a good baseline test this patch thoroughly, but at least I can bootstrap gcc without it failing in libgfortran. Is this OK for mainline and/or could someone see if it causes any regressions? I think instead of doing a run-time check I'd prefer something like the following, keeping the compile-time assert. --- a/libgfortran/intrinsics/random.c +++ b/libgfortran/intrinsics/random.c @@ -253 +253 @@ static GFC_UINTEGER_4 kiss_default_seed[] = { -static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); +#define KISS_SIZE ((GFC_INTEGER_4) (sizeof(kiss_seed)/sizeof(kiss_seed[0])) (plus s/kiss_size/KISS_SIZE/ changes in the code.) Janne, what do you think? I like it. With this, you can also get rid of the assert and the newly introduced KISS_MAX_SIZE macro, and just make the seed array the correct size, as was originally done (with a VLA). Consider such a patch pre-approved. Thanks for fixing this! Cesar #include stdint.h typedef int32_t GFC_INTEGER_4; typedef uint32_t GFC_UINTEGER_4; static const GFC_UINTEGER_4 kiss_seed[] = { 123456789, 362436069, 521288629, 316191069, 987654321, 458629013, 582859209, 438195021, 573658661, 185639104, 582619469, 296736107 }; static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); int main () { #define KISS_MAX_SIZE 12 unsigned char seed[4 * 12]; _Static_assert (kiss_size = 12, kiss_size must = KISS_MAX_SIZE); //static_assert (kiss_size = 12, kiss_size must = KISS_MAX_SIZE); return 0; }
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
Regtested on x86_64-unknown-linux-gnu, Ok for trunk? OK two me, with three comments: * intrinsics/chmod.c (chmod_internal): New function, move logic here. (chmod_func): Call chmod_internal. Not sure what’s the need / benefit from this, given the function is only called once. * intrinsics/random.c (random_seed_i4): Use static buffer rather than VLA, use _Static_assert to make sure it's big enough. This array has constant size, known at compilation time. Isn’t it allowed to have an array with “const int” as size? I though it was. * io/read.c (read_f): Likewise. Is the known upper bound you have chosen (#define READF_TMP 50) compatible with the largest float we support, i.e. real(16)? So that we avoid using allocation for reading data we have written ourselves in default format :) FX
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On Thu, Nov 13, 2014 at 1:31 PM, FX fxcoud...@gmail.com wrote: Regtested on x86_64-unknown-linux-gnu, Ok for trunk? OK two me, with three comments: * intrinsics/chmod.c (chmod_internal): New function, move logic here. (chmod_func): Call chmod_internal. Not sure what’s the need / benefit from this, given the function is only called once. Just a convenience; chmod_internal returns from quite a few places. Rather than sprinkling free() calls before all those, I used a wrapper function. As it's called only once, and it's a static function, it should be inlined anyway. * intrinsics/random.c (random_seed_i4): Use static buffer rather than VLA, use _Static_assert to make sure it's big enough. This array has constant size, known at compilation time. Isn’t it allowed to have an array with “const int” as size? I though it was. I originally thought so, but apparently not, as it fails to compile with -Werror=vla. Same for the other couple places where I replaced a static const variable with a macro. The reason might be that the const-ness can be casted away, and then one can write to the variable? * io/read.c (read_f): Likewise. Is the known upper bound you have chosen (#define READF_TMP 50) compatible with the largest float we support, i.e. real(16)? So that we avoid using allocation for reading data we have written ourselves in default format :) Yeah, I used the test program below: program maxgf implicit none print *, huge(0._10) print *, -huge(0._16) print *, '123456789012345678901234567890123456789012345678901234567890' end program maxgf = something like 45 characters should be enough. Then I added a few extra just to be sure to cover all the common cases. Thanks for the quick review, committed as r217480. -- Janne Blomqvist
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On Thu, Nov 13, 2014 at 02:05:52PM +0200, Janne Blomqvist wrote: Thanks for the quick review, committed as r217480. This broke bootstrap because of implicit declaration of free. The following (untested) should fix it, ok for trunk? 2014-11-13 Marek Polacek pola...@redhat.com * intrinsics/access.c: Include stdlib.h. * intrinsics/chdir.c: Likewise. * intrinsics/chmod.c: Likewise. diff --git gcc/intrinsics/access.c gcc/intrinsics/access.c index 65a0a10..0c18da0 100644 --- gcc/intrinsics/access.c +++ gcc/intrinsics/access.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h #ifdef HAVE_UNISTD_H diff --git gcc/intrinsics/chdir.c gcc/intrinsics/chdir.c index 87419a8..193e482 100644 --- gcc/intrinsics/chdir.c +++ gcc/intrinsics/chdir.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h #ifdef HAVE_UNISTD_H diff --git gcc/intrinsics/chmod.c gcc/intrinsics/chmod.c index c42fa8c..bdcb676 100644 --- gcc/intrinsics/chmod.c +++ gcc/intrinsics/chmod.c @@ -28,6 +28,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #if defined(HAVE_SYS_STAT_H) #include string.h/* For memcpy. */ +#include stdlib.h/* For free. */ #include sys/stat.h /* For stat, chmod and umask. */ Marek
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On Thu, Nov 13, 2014 at 04:57:08PM +0100, Marek Polacek wrote: On Thu, Nov 13, 2014 at 02:05:52PM +0200, Janne Blomqvist wrote: Thanks for the quick review, committed as r217480. This broke bootstrap because of implicit declaration of free. The following (untested) should fix it, ok for trunk? 2014-11-13 Marek Polacek pola...@redhat.com * intrinsics/access.c: Include stdlib.h. * intrinsics/chdir.c: Likewise. * intrinsics/chmod.c: Likewise. Ok, thanks. Jakub
Re: [PATCH, libgfortran] PR 60324 Unbounded stack allocations in libgfortran
On Thu, Nov 13, 2014 at 04:59:09PM +0100, Jakub Jelinek wrote: On Thu, Nov 13, 2014 at 04:57:08PM +0100, Marek Polacek wrote: On Thu, Nov 13, 2014 at 02:05:52PM +0200, Janne Blomqvist wrote: Thanks for the quick review, committed as r217480. This broke bootstrap because of implicit declaration of free. The following (untested) should fix it, ok for trunk? 2014-11-13 Marek Polacek pola...@redhat.com * intrinsics/access.c: Include stdlib.h. * intrinsics/chdir.c: Likewise. * intrinsics/chmod.c: Likewise. Ok, thanks. The previous version was incomplete. The following should be. Applying to trunk. 2014-11-13 Marek Polacek pola...@redhat.com * intrinsics/access.c: Include stdlib.h. * intrinsics/chdir.c: Likewise. * intrinsics/chmod.c: Likewise. * intrinsics/link.c: Likewise. * intrinsics/perror.c: Likewise. * intrinsics/rename.c: Likewise. * intrinsics/symlnk.c: Likewise. * intrinsics/unlink.c: Likewise. diff --git gcc/intrinsics/access.c gcc/intrinsics/access.c index 65a0a10..0c18da0 100644 --- gcc/intrinsics/access.c +++ gcc/intrinsics/access.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h #ifdef HAVE_UNISTD_H diff --git gcc/intrinsics/chdir.c gcc/intrinsics/chdir.c index 87419a8..193e482 100644 --- gcc/intrinsics/chdir.c +++ gcc/intrinsics/chdir.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h #ifdef HAVE_UNISTD_H diff --git gcc/intrinsics/chmod.c gcc/intrinsics/chmod.c index c42fa8c..bdcb676 100644 --- gcc/intrinsics/chmod.c +++ gcc/intrinsics/chmod.c @@ -28,6 +28,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #if defined(HAVE_SYS_STAT_H) #include string.h/* For memcpy. */ +#include stdlib.h/* For free. */ #include sys/stat.h /* For stat, chmod and umask. */ diff --git gcc/intrinsics/link.c gcc/intrinsics/link.c index c6084a1..dd9c470 100644 --- gcc/intrinsics/link.c +++ gcc/intrinsics/link.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h #ifdef HAVE_UNISTD_H diff --git gcc/intrinsics/perror.c gcc/intrinsics/perror.c index a8f0972..2bb1305 100644 --- gcc/intrinsics/perror.c +++ gcc/intrinsics/perror.c @@ -27,6 +27,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include errno.h #include string.h +#include stdlib.h /* SUBROUTINE PERROR(STRING) CHARACTER(len=*), INTENT(IN) :: STRING */ diff --git gcc/intrinsics/rename.c gcc/intrinsics/rename.c index aabf821..78c3d81 100644 --- gcc/intrinsics/rename.c +++ gcc/intrinsics/rename.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h diff --git gcc/intrinsics/symlnk.c gcc/intrinsics/symlnk.c index 5c53cb7..52a3c4b 100644 --- gcc/intrinsics/symlnk.c +++ gcc/intrinsics/symlnk.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h #include errno.h +#include stdlib.h #include string.h #ifdef HAVE_UNISTD_H diff --git gcc/intrinsics/unlink.c gcc/intrinsics/unlink.c index 2971a62..4752988 100644 --- gcc/intrinsics/unlink.c +++ gcc/intrinsics/unlink.c @@ -25,6 +25,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include libgfortran.h +#include stdlib.h #include string.h #include errno.h Marek