Creation of Class Instance within a Static Code Block
Description
Creation of Class Instance within a Static Code Block occurs when a product contains a static code block that creates a class instance, either directly or indirectly. Static initializers run when the class is loaded, which happens once per classloader and at an unpredictable time. Creating instances in static blocks can lead to initialization order problems, resource leaks, exception handling difficulties, and testing challenges. The instance is created before the application is fully initialized, potentially leading to incomplete configuration or missing dependencies.
Risk
This pattern creates reliability and potential security risks. Exceptions thrown during static initialization cause ExceptionInInitializerError, which is difficult to handle and debug. Resources allocated in static blocks may never be properly released. The unpredictable timing of class loading can cause race conditions. Security-sensitive initialization might occur before security context is established. Configuration or dependencies may not be available during static initialization. Static instances are difficult to mock for security testing, potentially leaving security paths untested. Memory leaks can occur if the static instance holds references that prevent garbage collection.
Solution
Use lazy initialization instead of static blocks. Apply the singleton pattern with proper lazy initialization (double-checked locking, initialization-on-demand holder, or enum singleton). Use dependency injection frameworks to manage instance lifecycle. Defer initialization until the application context is fully established. If static initialization is necessary, keep it simple and handle exceptions properly. Consider using factory patterns for instance creation. For testing, design classes to allow dependency injection rather than creating instances in static contexts.
Common Consequences
| Impact | Details |
|---|---|
| Other | Scope: Other Reduce Reliability - Static initialization failures cause hard-to-debug class loading errors. |
| Other | Scope: Other Reduce Maintainability - Static instances are difficult to test and mock. |
| Availability | Scope: Availability DoS: Resource Consumption - Resources allocated in static blocks may leak if not properly managed. |
Example Code
Vulnerable Code
// Vulnerable: Creating instances in static initializer
public class VulnerableConfiguration {
// Vulnerable: Instance created during class loading
private static final DatabaseConnection dbConnection;
private static final ConfigurationLoader configLoader;
private static final SecurityManager securityManager;
static {
// Vulnerable: All of these can fail during class loading
try {
// Database might not be available yet
dbConnection = new DatabaseConnection("jdbc:mysql://localhost/db");
// Config file might not be accessible
configLoader = new ConfigurationLoader("/etc/app/config.xml");
// Security context might not be established
securityManager = new SecurityManager(configLoader.getSecuritySettings());
} catch (Exception e) {
// This exception wraps into ExceptionInInitializerError
// and makes the class unusable
throw new RuntimeException("Failed to initialize", e);
}
}
public static DatabaseConnection getDatabase() {
return dbConnection; // Returns null if initialization failed partially
}
}
// Problems:
// 1. If database is down at startup, class cannot be loaded
// 2. Partial initialization leaves system in inconsistent state
// 3. Cannot retry initialization after failure
// 4. Cannot mock for testing
# Vulnerable: Creating instances at module import time
# config.py
# Vulnerable: These execute when module is imported
_database = None
_config = None
# Vulnerable: Module-level initialization
try:
# Executes during import - before app is ready
_config = ConfigurationLoader('/etc/app/config.yaml')
# Database credentials might not be available yet
_database = DatabaseConnection(
host=_config.get('db_host'),
password=_config.get('db_password') # Might be None!
)
except Exception as e:
# Module import fails entirely
print(f"Failed to initialize: {e}")
# But _database and _config might be partially set
class VulnerableService:
# Vulnerable: Class attribute initialized at import time
_instance = None
_cache = HeavyCache(size_mb=100) # 100MB allocated at import!
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
# Just importing this module:
# 1. Tries to connect to database
# 2. Allocates 100MB for cache
# 3. Might fail and leave module in bad state
// Vulnerable: Static constructor with instance creation
public class VulnerableLogger
{
// Vulnerable: Static field with inline initialization
private static readonly FileStream logFile =
new FileStream("/var/log/app.log", FileMode.Append);
private static readonly VulnerableLogger instance;
private static readonly object lockObj = new object();
// Vulnerable: Static constructor
static VulnerableLogger()
{
// If this fails, class becomes permanently unusable
try
{
// External service might not be available
var config = RemoteConfigService.FetchConfig();
instance = new VulnerableLogger(config);
// Resource allocated but might not be released
var networkStream = new NetworkStream(
new TcpClient(config.LogServer, config.LogPort).GetStream()
);
}
catch (Exception ex)
{
// TypeInitializationException will be thrown on any access
throw new InvalidOperationException("Logger initialization failed", ex);
}
}
public static void Log(string message)
{
// Will throw TypeInitializationException if static ctor failed
instance.WriteLog(message);
}
}
// Vulnerable: C++ static initialization order fiasco
// file1.cpp
class VulnerableGlobalConfig {
public:
static VulnerableGlobalConfig& getInstance() {
// Vulnerable: Static local variable
static VulnerableGlobalConfig instance;
return instance;
}
std::string getValue(const std::string& key) {
return config_[key];
}
private:
VulnerableGlobalConfig() {
// Vulnerable: Uses another static that might not be initialized
auto& logger = VulnerableLogger::getInstance();
logger.log("Loading config...");
// Load configuration...
}
std::map<std::string, std::string> config_;
};
// file2.cpp
class VulnerableLogger {
public:
static VulnerableLogger& getInstance() {
static VulnerableLogger instance;
return instance;
}
void log(const std::string& msg) {
// Vulnerable: Uses config that might not be initialized
auto& config = VulnerableGlobalConfig::getInstance();
std::string level = config.getValue("log_level"); // Circular!
// ...
}
};
// Static initialization order between translation units is undefined!
Fixed Code
// Fixed: Lazy initialization with proper lifecycle management
public class FixedConfiguration {
// Fixed: No static instance creation
private static volatile FixedConfiguration instance;
private final DatabaseConnection dbConnection;
private final ConfigurationLoader configLoader;
private final SecurityManager securityManager;
// Fixed: Private constructor - controlled initialization
private FixedConfiguration(ConfigurationLoader config) throws ConfigurationException {
this.configLoader = config;
this.dbConnection = createDatabaseConnection(config);
this.securityManager = createSecurityManager(config);
}
// Fixed: Lazy initialization with double-checked locking
public static FixedConfiguration getInstance() throws ConfigurationException {
if (instance == null) {
synchronized (FixedConfiguration.class) {
if (instance == null) {
// Load configuration only when needed
ConfigurationLoader config = new ConfigurationLoader(
System.getProperty("config.path", "/etc/app/config.xml")
);
instance = new FixedConfiguration(config);
}
}
}
return instance;
}
// Fixed: Alternative - Initialization-on-demand holder idiom
private static class Holder {
// Only created when Holder class is accessed
static final FixedConfiguration INSTANCE = createInstance();
private static FixedConfiguration createInstance() {
try {
ConfigurationLoader config = new ConfigurationLoader(
System.getProperty("config.path")
);
return new FixedConfiguration(config);
} catch (Exception e) {
throw new IllegalStateException("Configuration failed", e);
}
}
}
public static FixedConfiguration getInstanceLazy() {
return Holder.INSTANCE;
}
// Fixed: Allow injection for testing
public static void setInstance(FixedConfiguration testInstance) {
instance = testInstance;
}
private DatabaseConnection createDatabaseConnection(ConfigurationLoader config)
throws ConfigurationException {
// Can properly handle failures and retry
return new DatabaseConnection(config.getDatabaseUrl());
}
private SecurityManager createSecurityManager(ConfigurationLoader config)
throws ConfigurationException {
return new SecurityManager(config.getSecuritySettings());
}
}
# Fixed: Lazy initialization with proper lifecycle
from functools import lru_cache
from threading import Lock
from typing import Optional
class FixedConfiguration:
"""Configuration with lazy initialization"""
_instance: Optional['FixedConfiguration'] = None
_lock = Lock()
def __init__(self, config_path: str):
# Fixed: Constructor can be called when ready
self._config_path = config_path
self._loaded = False
self._config_data = None
def _ensure_loaded(self):
"""Lazy load configuration on first access"""
if not self._loaded:
self._config_data = self._load_config()
self._loaded = True
def _load_config(self):
# Load configuration - called only when needed
import yaml
with open(self._config_path) as f:
return yaml.safe_load(f)
@classmethod
def get_instance(cls, config_path: str = '/etc/app/config.yaml') -> 'FixedConfiguration':
"""Thread-safe lazy singleton"""
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = cls(config_path)
return cls._instance
@classmethod
def reset_instance(cls):
"""Allow resetting for testing"""
with cls._lock:
cls._instance = None
class FixedService:
"""Service with dependency injection"""
def __init__(self, config: FixedConfiguration, cache: Optional['Cache'] = None):
# Fixed: Dependencies injected, not created statically
self._config = config
self._cache = cache or self._create_default_cache()
def _create_default_cache(self) -> 'Cache':
# Fixed: Cache created lazily when service is instantiated
cache_size = self._config.get('cache_size_mb', 10)
return Cache(size_mb=cache_size)
# Fixed: Factory function for controlled initialization
def create_service(config_path: str = '/etc/app/config.yaml') -> FixedService:
"""Factory function - creates service when called, not at import"""
config = FixedConfiguration.get_instance(config_path)
return FixedService(config)
// Fixed: Lazy initialization with proper resource management
public sealed class FixedLogger : IDisposable
{
private static readonly Lazy<FixedLogger> lazyInstance =
new Lazy<FixedLogger>(() => CreateInstance(), LazyThreadSafetyMode.ExecutionAndPublication);
private readonly StreamWriter logWriter;
private readonly object writeLock = new object();
private bool disposed = false;
// Fixed: Private constructor
private FixedLogger(StreamWriter writer)
{
this.logWriter = writer;
}
// Fixed: Lazy initialization with proper error handling
private static FixedLogger CreateInstance()
{
try
{
var logPath = Environment.GetEnvironmentVariable("LOG_PATH") ?? "/var/log/app.log";
var writer = new StreamWriter(logPath, append: true);
return new FixedLogger(writer);
}
catch (Exception ex)
{
// Return a null logger instead of failing class loading
Console.Error.WriteLine($"Logger initialization failed: {ex.Message}");
return new FixedLogger(StreamWriter.Null);
}
}
// Fixed: Instance only created when first accessed
public static FixedLogger Instance => lazyInstance.Value;
public void Log(string message)
{
if (disposed) return;
lock (writeLock)
{
logWriter.WriteLine($"{DateTime.UtcNow:O}: {message}");
logWriter.Flush();
}
}
// Fixed: Proper resource cleanup
public void Dispose()
{
if (!disposed)
{
disposed = true;
logWriter?.Dispose();
}
}
}
// Fixed: C++ with proper initialization order
#include <memory>
#include <mutex>
#include <functional>
// Fixed: Use Meyers' Singleton with controlled initialization
class FixedConfig {
public:
// Fixed: Returns reference, initialization order controlled
static FixedConfig& getInstance() {
static FixedConfig instance;
return instance;
}
void initialize(const std::string& configPath) {
std::lock_guard<std::mutex> lock(initMutex_);
if (!initialized_) {
loadConfig(configPath);
initialized_ = true;
}
}
std::string getValue(const std::string& key) const {
if (!initialized_) {
throw std::runtime_error("Config not initialized");
}
auto it = config_.find(key);
return it != config_.end() ? it->second : "";
}
private:
FixedConfig() = default;
void loadConfig(const std::string& path) {
// Load configuration from file
}
std::map<std::string, std::string> config_;
std::mutex initMutex_;
bool initialized_ = false;
};
// Fixed: Logger with no circular dependency
class FixedLogger {
public:
static FixedLogger& getInstance() {
static FixedLogger instance;
return instance;
}
void log(const std::string& msg) {
// Fixed: No dependency on config during logging
std::cout << msg << std::endl;
}
private:
FixedLogger() = default;
};
// Fixed: Controlled initialization order in main
int main() {
// Explicit initialization order
FixedConfig::getInstance().initialize("/etc/app/config.yaml");
FixedLogger::getInstance().log("Application starting");
return 0;
}
CVE Examples
This CWE is marked as PROHIBITED for direct CVE mapping as it represents a code quality/design concern rather than a direct security vulnerability.
Related CWEs
- CWE-710: Improper Adherence to Coding Standards (parent)
- CWE-543: Use of Singleton Pattern Without Synchronization (related)
- CWE-1058: Invokable Control Element in Multi-Thread Context with non-Final Static (related)
References
- MITRE Corporation. "CWE-1063: Creation of Class Instance within a Static Code Block." https://cwe.mitre.org/data/definitions/1063.html
- Bloch, Joshua. "Effective Java, Third Edition." Item 83: Use lazy initialization judiciously.
- Oracle. "Java Language Specification - Initialization."