CON05-F. Ensure correct OpenMP datascoping of variables in parallel regions
Developers shall correctly specify data-sharing attributes ( shared , private , lastprivate , etc.) for all variables in OpenMP parallel regions to prevent data races, undefined behavior, and incorrect results.
In multithreaded code, data races occur when multiple threads access the same memory location concurrently, with at least one write and no proper synchronization. Incorrect OpenMP data-scoping manifests mainly in three ways:
- Incorrect sharing: A variable that should be local to each thread (e.g., loop iterators) is implicitly shared, causing threads to overwrite the same memory location.
- Incorrect privatization: A variable intended to aggregate results or maintain ga lobal state is declared
private, so each thread updates its local copy, and changes are lost. - Missing
lastprivate: A variable correctly privatized for a loop does not retain the value from the logically last iteration, leading to inconsistent post-loop results.
Using default(none) in combination with explicit attribute declarations enforces safe, predictable data-scoping and prevents accidental sharing or privatization errors.
Noncompliant Code Example
In this example, the temporary variable scaling_factor is shared among all threads because it is not declared private. Each thread overwrites the same memory location, causing a data race when multiple threads simultaneously compute and assign to A(i) .
subroutine apply_weights(A, B, weight)
implicit none
real, intent(inout) :: A(:)
real, intent(in) :: B(:), weight
real :: scaling_factor
integer :: i
!$omp parallel do shared(A, B, weight, scaling_factor)
do i = 1, size(A)
scaling_factor = B(i) * weight
A(i) = A(i) + scaling_factor
end do
end subroutine
Compliant Solution
The compliant solution uses default(none) and explicitly marks the scalar as private so each thread has its own isolated instance. Note that the variable i is implicitly private as it is the iteration variable.
! Compliant: scaling_factor is now local to each thread.
!$omp parallel do default(none) shared(A, B, weight) private(scaling_factor)
do i = 1, size(A)
scaling_factor = B(i) * weight
A(i) = A(i) + scaling_factor
end do
Noncompliant Code Example
In this example, the programmer intends to populate the results array. However, by marking results as private , the threads operate on local copies that are not synchronized with the actual array on the host. Consequently, the results array remains unchanged after the subroutine executes.
subroutine compute_log(input, results)
implicit none
real, intent(in) :: input(:)
real, intent(inout) :: results(:)
integer :: i
! Noncompliant: results array is privatized; host updates are lost
!$omp parallel do private(i, results) shared(input)
do i = 1, size(input)
results(i) = log(input(i))
end do
end subnroutine
Compliant Solution
In the compliant version, the results array is no longer privatized. Instead, it is explicitly declared as shared , ensuring that updates performed by each thread are applied to the host-visible array. Using default(none) enforces explicit data-sharing attributes and prevents accidental privatization.
! Compliant: results is shared so updates are visible outside the region
!$omp parallel do default(none) private(i) shared(input, results)
Noncompliant Code Example
In this example, the programmer intends to populate the results array. However, by marking results as private , the threads operate on local copies that are not synchronized with the actual array on the host. Consequently, the results array remains unchanged after the subroutine executes.
real function process_increment(data)
implicit none
real, intent(in) :: data(:)
real :: last_val
integer :: i
! Noncompliant: last_val is private, so tis value is lost after
! the loop.
!$omp parallel do private(i, last_val) shared(data)
do i = 1, size(data)
last_val = data(i) * 2.0
end do
process_increment = last_val + 10.0
end function
Compliant Solution
The lastprivate clause ensures that the value from the iteration that would be the last in a sequential execution is copied back to the host variable.
! Compliant: lastprivate preserves the value for use after the loop
!$omp parallel do default(none) lastprivate(last_val) shared(data) private(i)
Risk Assessment
Incorrect OpenMP data-scoping can lead to data races, causing non-deterministic behavior and potential security vulnerabilities.
| Recommendation | Severity | Likelihood | Detectable | Repairable | Priority | Level |
| CON05-F | High | Likely | Yes | Yes | P27 | L1 |
Attachments:
button_arrow_left.png (image/png)
button_arrow_up.png (image/png)
button_arrow_right.png (image/png)


