Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions Checks/PWR080/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,24 @@ them.
Consider the following code, which sums the elements of an array after applying
the specified transformation:

```c {8,24} showLineNumbers
```c {14,30} showLineNumbers
// example.c
#include <stdio.h>
#include <string.h>

double transform_and_sum(const double *array, size_t size, const char *option) {
typedef enum {
OPTION_HALF,
OPTION_DOUBLE,
OPTION_UNKNOWN,
} TransformOption;

double transform_and_sum(const double *array, size_t size,
TransformOption option) {
double sum = 0.0;

double factor;
if (strcmp(option, "half") == 0) {
if (option == OPTION_HALF) {
factor = 0.5;
} else if (strcmp(option, "double") == 0) {
} else if (option == OPTION_DOUBLE) {
factor = 2.0;
}

Expand All @@ -80,7 +86,7 @@ double transform_and_sum(const double *array, size_t size, const char *option) {

int main() {
double array[] = {0.25, 0.25, 0.25, 0.25};
printf("Sum is: %f\n", transform_and_sum(array, 4, "unknownOption"));
printf("Sum is: %f\n", transform_and_sum(array, 4, OPTION_UNKNOWN));

return 0;
}
Expand All @@ -89,7 +95,7 @@ int main() {
Note how `factor`, an automatic variable, is only explicitly initialized when
the received `option` is known. Since the C standard does not guarantee any
specific initial value, the state of `factor` is indeterminate in the previous
scenario (using an `unknownOption`), leading to different outcomes depending on
scenario (using `OPTION_UNKNOWN`), leading to different outcomes depending on
the compiler and its settings:

- For instance, `gcc -O2` behaves as if the `if` branch was taken:
Expand Down Expand Up @@ -136,34 +142,42 @@ double factor = 1.0;
Consider the following code, which sums the elements of an array after applying
the specified transformation:

```fortran {9,20} showLineNumbers
```fortran {17,28} showLineNumbers
! example.f90

module options
integer, parameter :: OPTION_HALF = 1
integer, parameter :: OPTION_DOUBLE = 2
integer, parameter :: OPTION_UNKNOWN = 3
end module options

program main
use iso_fortran_env, only: real32
use options, only: OPTION_HALF, OPTION_DOUBLE, OPTION_UNKNOWN
implicit none

real(kind=real32) :: array(4)
array = [0.25, 0.25, 0.25, 0.25]

print *, "Sum is:", transform_and_sum(array, "unknownOption")
print *, "Sum is:", transform_and_sum(array, OPTION_UNKNOWN)

contains

real(kind=real32) function transform_and_sum(array, option)
implicit none

real(kind=real32), intent(in) :: array(:)
character(len=*), intent(in) :: option
integer, intent(in) :: option

real(kind=real32) :: sum
real(kind=real32) :: factor
integer :: i

sum = 0.0

if (option == "half") then
if (option == OPTION_HALF) then
factor = 0.5
else if (option == "double") then
else if (option == OPTION_DOUBLE) then
factor = 2.0
end if

Expand All @@ -180,7 +194,7 @@ end program main
Note how `factor` is only explicitly initialized when the received `option` is
known. Since the Fortran standard does not guarantee any specific initial
value, the state of `factor` is indeterminate in the previous scenario (using
an `unknownOption`), leading to different outcomes depending on the compiler
`OPTION_UNKNOWN`), leading to different outcomes depending on the compiler
and its settings:

- For instance, `gfortran -O2` behaves as if the `if` branch was taken:
Expand Down
16 changes: 11 additions & 5 deletions Checks/PWR080/example.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
// PWR080: Conditionally initialized variables can lead to undefined behavior

#include <stdio.h>
#include <string.h>

double transform_and_sum(const double *array, size_t size, const char *option) {
typedef enum {
OPTION_HALF,
OPTION_DOUBLE,
OPTION_UNKNOWN,
} TransformOption;

double transform_and_sum(const double *array, size_t size,
TransformOption option) {
double sum = 0.0;

double factor;
if (strcmp(option, "half") == 0) {
if (option == OPTION_HALF) {
factor = 0.5;
} else if (strcmp(option, "double") == 0) {
} else if (option == OPTION_DOUBLE) {
factor = 2.0;
}

Expand All @@ -22,7 +28,7 @@ double transform_and_sum(const double *array, size_t size, const char *option) {

int main() {
double array[] = {0.25, 0.25, 0.25, 0.25};
printf("Sum is: %f\n", transform_and_sum(array, 4, "unknownOption"));
printf("Sum is: %f\n", transform_and_sum(array, 4, OPTION_UNKNOWN));

return 0;
}
15 changes: 11 additions & 4 deletions Checks/PWR080/example.f90
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
! PWR080: Conditionally initialized variables can lead to undefined behavior

module options
integer, parameter :: OPTION_HALF = 1
integer, parameter :: OPTION_DOUBLE = 2
integer, parameter :: OPTION_UNKNOWN = 3
end module options

program main
use iso_fortran_env, only: real32
use options, only: OPTION_HALF, OPTION_DOUBLE, OPTION_UNKNOWN
implicit none

real(kind=real32) :: array(4)
array = [0.25, 0.25, 0.25, 0.25]

print *, "Sum is:", transform_and_sum(array, "unknownOption")
print *, "Sum is:", transform_and_sum(array, OPTION_UNKNOWN)

contains

real(kind=real32) function transform_and_sum(array, option)
implicit none

real(kind=real32), intent(in) :: array(:)
character(len=*), intent(in) :: option
integer, intent(in) :: option

real(kind=real32) :: sum
real(kind=real32) :: factor
integer :: i

sum = 0.0

if (option == "half") then
if (option == OPTION_HALF) then
factor = 0.5
else if (option == "double") then
else if (option == OPTION_DOUBLE) then
factor = 2.0
end if

Expand Down
16 changes: 11 additions & 5 deletions Checks/PWR080/solution.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
// PWR080: Conditionally initialized variables can lead to undefined behavior

#include <stdio.h>
#include <string.h>

double transform_and_sum(const double *array, size_t size, const char *option) {
typedef enum {
OPTION_HALF,
OPTION_DOUBLE,
OPTION_UNKNOWN,
} TransformOption;

double transform_and_sum(const double *array, size_t size,
TransformOption option) {
double sum = 0.0;

// Identity transformation by default
double factor = 1.0;
if (strcmp(option, "half") == 0) {
if (option == OPTION_HALF) {
factor = 0.5;
} else if (strcmp(option, "double") == 0) {
} else if (option == OPTION_DOUBLE) {
factor = 2.0;
}

Expand All @@ -23,7 +29,7 @@ double transform_and_sum(const double *array, size_t size, const char *option) {

int main() {
double array[] = {0.25, 0.25, 0.25, 0.25};
printf("Sum is: %f\n", transform_and_sum(array, 4, "unknownOption"));
printf("Sum is: %f\n", transform_and_sum(array, 4, OPTION_UNKNOWN));

return 0;
}
15 changes: 11 additions & 4 deletions Checks/PWR080/solution.f90
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
! PWR080: Conditionally initialized variables can lead to undefined behavior

module options
integer, parameter :: OPTION_HALF = 1
integer, parameter :: OPTION_DOUBLE = 2
integer, parameter :: OPTION_UNKNOWN = 3
end module options

program main
use iso_fortran_env, only: real32
use options, only: OPTION_HALF, OPTION_DOUBLE, OPTION_UNKNOWN
implicit none

real(kind=real32) :: array(4)
array = [0.25, 0.25, 0.25, 0.25]

print *, "Sum is:", transform_and_sum(array, "unknownOption")
print *, "Sum is:", transform_and_sum(array, OPTION_UNKNOWN)

contains

real(kind=real32) function transform_and_sum(array, option)
implicit none

real(kind=real32), intent(in) :: array(:)
character(len=*), intent(in) :: option
integer, intent(in) :: option

real(kind=real32) :: sum
real(kind=real32) :: factor
Expand All @@ -25,9 +32,9 @@ real(kind=real32) function transform_and_sum(array, option)
! Identity transformation by default
factor = 1.0

if (option == "half") then
if (option == OPTION_HALF) then
factor = 0.5
else if (option == "double") then
else if (option == OPTION_DOUBLE) then
factor = 2.0
end if

Expand Down