Skip to main content
GitHub

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.

Non-compliant code
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.

Compliant code
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.

Compliant code
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.

RecommendationSeverityLikelihoodDetectableRepairablePriorityLevel
SAD02-FHighUnlikelyYesNoP6L2

Bibliography

[ Fortran 2023 Interpretation Document ]Section B.3.11, C.10.2.2, 8.10.2, and 14.2.2

Attachments: