SAD03-F. Replace common block with modules for safer data encapsulation
Shared data should be encapsulated in modules rather than using common blocks to ensure type safety, consistent naming, and minimal scope.
The common statement is a legacy Fortran feature that specifies a block of memory shared across program units. The Fortran standard now identifies common blocks as obsolescent, noting that they are error-prone, inhibit maintainability, and can impact performance.
Relying on common blocks introduces several risks:
- Lack of type safety: Different program units can associate conflicting types with the same memory location, potentially causing memory corruption.
- Name inconsistency: Each procedure must redeclare the common block, leading to inconsistent names and difficult-to-audit logic.
- Global scope vulnerabilities: Using a larger scope than necessary makes code less readable and increases the likelihood of referencing unintended variables.
Modules provide a superior alternative by allowing controlled access to data through the use statement and the only clause, allowing the compiler to enforce type, rank, and scope consistency.
Noncompliant Code Example
In this noncompliant example, the main program shares two variables via a common block. However, the subroutine update_kinetics re-defines the common block but omits the first variable ( mass ). Consequently, the local variable velocity in the subroutine unintentionally references the memory location assigned to mass in the main program.
program physics_sim
implicit none
real :: mass, velocity
! Noncompliant: Global memory shared via common block
common /sim_data/ mass, velocity
mass = 10.0
velocity = 50.0
call update_kinetics
end program physics_sim
subroutine update_kinetics
implicit none
real :: velocity
! Noncompliant: Re-declaration is missing 'mass'
common /sim_data/ velocity
print *, "Velocity inside subroutine: ", velocity
end subroutine update_kinetics
Compliant Solution
In this compliant solution, the variables are migrated to a module. This ensures that every programming unit accessing mass or velocity refers to the same unique identifier and correct data type.
module physics_data_mod
implicit none
! Compliant: Data is encapsulated and type-checked
real :: mass, velocity
end module physics_data_mod
program physics_sim
use physics_data_mod, only: mass, velocity
implicit none
mass = 10.0
velocity = 50.0
call update_kinetics
end program physics_sim
subroutine update_kinetics
use physics_data_mod, only: velocity
implicit none
! Compliant: velocity correctly refers to the shared module variable
print *, "Velocity inside subroutine: ", velocity
end subroutine update_kinetics
Compliant Solution
For maximum security and encapsulation, module variables should be declared PRIVATE , with access managed through PUBLIC getter and setter procedures. This follows the principle of minimizing the scope by ensuring variables are only modified through controlled interfaces.
module kinetics_mod
implicit none
private
real :: velocity
public :: get_velocity, set_velocity
contains
function get_velocity() result(v)
real :: v
v = velocity
end function
subroutine set_velocity(v)
real, intent(in) :: v
velocity = v
end subroutine
end module kinetics_mod
Risk Assessment
Using common blocks bypasses compiler checks and obscures data flow, increasing the likelihood of memory corruption, subtle logic errors, and unpredictable behavior in scientific computations.
| Recommendation | Severity | Likelihood | Detectable | Repairable | Priority | Level |
| SAD02-F | High | Unlikely | Yes | No | P6 | L2 |
Bibliography
| [ Fortran 2023 Interpretation Document ] | Section B.3.11, C.10.2.2, 8.10.2, and 14.2.2 |
Attachments:
button_arrow_left.png (image/png)
button_arrow_up.png (image/png)
button_arrow_right.png (image/png)


