Leerer Codeblock

Beschreibung

Leerer Codeblock tritt auf, wenn Quellcode einen Block enthält, der keinen Code enthält - der Block ist leer. Dies umfasst leere Funktionsrümpfe, leere bedingte Verzweigungen (if/else), leere Schleifen, leere Ausnahmebehandler und leere synchronized-Blöcke. Leere Blöcke deuten typischerweise auf unvollständige Implementierung, versehentlich gelöschten Code oder Restcode vom Refactoring hin. Obwohl manchmal beabsichtigt, sind leere Blöcke ein Code-Smell, der oft auf einen Fehler oder fehlende Funktionalität hinweist.

Risiko

Leere Codeblöcke haben verschiedene Sicherheitsimplikationen je nach Kontext. Leere Ausnahmebehandler (Catch-Blöcke) verschlucken stillschweigend Fehler und verstecken möglicherweise Sicherheitsfehler. Leere synchronized-Blöcke bieten keine Thread-Sicherheit, obwohl sie Schutz suggerieren. Leere bedingte Verzweigungen können auf fehlende Sicherheitsprüfungen hindeuten. Leere Funktionsrümpfe lassen möglicherweise Sicherheits-Callbacks unimplementiert. Leere Schleifen können unendliche Blockaden verursachen, wenn die Abbruchbedingung nie erfüllt wird. Das täuschende Erscheinungsbild funktionalen Codes führt Code-Reviewer in die Irre und lässt sie glauben, dass Sicherheitskontrollen existieren, wenn sie es nicht tun.

Lösung

Überprüfen Sie alle leeren Codeblöcke auf Absicht. Wenn beabsichtigt, fügen Sie einen Kommentar hinzu, der erklärt warum der Block leer ist. Wenn unbeabsichtigt, implementieren Sie die fehlende Funktionalität. Verwenden Sie statische Analysetools, um leere Blöcke zu erkennen. Für Ausnahmebehandler protokollieren Sie zumindest die Ausnahme. Für synchronized-Blöcke entfernen Sie sie wenn unnötig oder implementieren Sie ordnungsgemäße Synchronisation. Erwägen Sie die Verwendung von TODO-Kommentaren oder Assertions, um unvollständige Implementierungen zu markieren. Etablieren Sie Coding-Standards, die Begründung für leere Blöcke erfordern.

Häufige Auswirkungen

AuswirkungDetails
AndereBereich: Ändere

Reduzierte Zuverlässigkeit - Leere Blöcke können auf fehlende Funktionalität hindeuten, die das Systemverhalten beeinflusst.
AndereBereich: Ändere

Variiert je nach Kontext - Auswirkung hängt davon ab, was der leere Block hätte enthalten sollen.
IntegritätBereich: Integrität

Unerwarteter Zustand - Leere Handler können das System nach Fehlern in ungültigen Zuständen belassen.

Beispielcode

Anfälliger Code

// Anfällig: Verschiedene leere Codeblöcke
public class VulnerableProcessor {

    // Anfällig: Leerer Methodenrumpf
    public void validateInput(String input) {
        // Fehlende Validierungsimplementierung!
    }

    // Anfällig: Leerer Ausnahmebehandler
    public void processData(String data) {
        try {
            riskyOperation(data);
        } catch (Exception e) {
            // Leerer Catch - Ausnahme stillschweigend ignoriert!
        }
    }

    // Anfällig: Leerer synchronized-Block
    private int counter = 0;

    public void incrementCounter() {
        synchronized (this) {
            // Leerer sync-Block bietet keinen Schutz!
        }
        counter++;  // Dies ist immer noch ungeschützt!
    }

    // Anfällig: Leere if/else-Verzweigungen
    public void handleRequest(Request request) {
        if (request.isAuthenticated()) {
            // Sollte authentifizierte Anfragen verarbeiten
        } else {
            // Sollte unauthentifizierte behandeln - tut nichts!
        }
    }

    // Anfällig: Leerer Schleifenrumpf
    public void waitForCondition() {
        while (!condition) {
            // Leere Schleife - potenzieller CPU-Spin/Endlosschleife
        }
    }

    // Anfällig: Leerer finally-Block
    public void cleanupResources() {
        try {
            allocateResource();
        } finally {
            // Bereinigungscode fehlt!
        }
    }
}
# Anfällig: Leere Codeblöcke in Python
class VulnerableService:

    def validate_credentials(self, username, password):
        """Sollte Benutzer-Credentials validieren"""
        pass  # Leere Implementierung!

    def process_payment(self, amount):
        try:
            charge_card(amount)
        except PaymentError:
            pass  # Zahlungsfehler stillschweigend ignoriert!
        except Exception:
            pass  # Alle Fehler ignoriert!

    def handle_security_event(self, event):
        if event.severity == 'CRITICAL':
            pass  # Kritische Ereignisse ignoriert!
        elif event.severity == 'HIGH':
            pass  # Hoher Schweregrad ignoriert!
        else:
            pass  # Alles ignoriert!

    def acquire_lock(self):
        with self._lock:
            pass  # Leerer Context-Manager - kein geschützter Code!
        self._shared_data += 1  # Ungeschützt!
// Anfällig: Leere Codeblöcke in C#
public class VulnerableHandler
{
    // Anfällig: Leere Methode
    public virtual void OnSecurityEvent(SecurityEvent evt)
    {
        // Unterklasse vergisst möglicherweise zu überschreiben - Ereignis verloren!
    }

    // Anfällig: Leerer Catch
    public void SaveData(object data)
    {
        try
        {
            _database.Save(data);
        }
        catch (SqlException)
        {
            // Datenbankfehler stillschweigend ignoriert!
        }
    }

    // Anfällig: Leerer lock-Block
    private readonly object _lockObj = new object();
    private int _value;

    public void UpdateValue(int newValue)
    {
        lock (_lockObj)
        {
            // Leerer lock - bietet keinen Schutz!
        }
        _value = newValue;  // Immer noch ungeschützt!
    }

    // Anfällig: Leere Bedingung
    public void ProcessInput(string input)
    {
        if (IsMalicious(input))
        {
            // Sollte bösartige Eingabe blockieren - tut nichts!
        }
        // Verarbeitet weiter potenziell bösartige Eingabe
        ExecuteCommand(input);
    }
}

Korrigierter Code

// Korrigiert: Ordnungsgemäße Implementierung von Codeblöcken
public class FixedProcessor {

    private static final Logger logger = LoggerFactory.getLogger(FixedProcessor.class);

    // Korrigiert: Implementierte Validierung
    public void validateInput(String input) throws ValidationException {
        if (input == null || input.trim().isEmpty()) {
            throw new ValidationException("Eingabe darf nicht null oder leer sein");
        }
        if (input.contains("<script>")) {
            throw new ValidationException("Potenzielles XSS erkannt");
        }
        // Zusätzliche Validierung...
    }

    // Korrigiert: Ordnungsgemäße Ausnahmebehandlung
    public void processData(String data) throws ProcessingException {
        try {
            riskyOperation(data);
        } catch (IOException e) {
            logger.error("IO-Fehler bei Datenverarbeitung", e);
            throw new ProcessingException("Datenverarbeitung fehlgeschlagen", e);
        } catch (Exception e) {
            logger.error("Unerwarteter Fehler bei Datenverarbeitung", e);
            throw new ProcessingException("Verarbeitung fehlgeschlagen", e);
        }
    }

    // Korrigiert: Synchronized-Block enthält geschützten Code
    private int counter = 0;

    public void incrementCounter() {
        synchronized (this) {
            counter++;  // Durch Synchronisation geschützt
        }
    }

    // Korrigiert: Implementierte bedingte Verzweigungen
    public void handleRequest(Request request) throws SecurityException {
        if (request.isAuthenticated()) {
            processAuthenticatedRequest(request);
        } else {
            logger.warn("Unauthentifizierter Anfragversuch von {}",
                request.getRemoteAddr());
            throw new SecurityException("Authentifizierung erforderlich");
        }
    }

    // Korrigiert: Schleife hat ordnungsgemäßen Rumpf
    public void waitForCondition() throws TimeoutException {
        long startTime = System.currentTimeMillis();
        long timeout = 30000;

        while (!condition) {
            // Korrigiert: Ordnungsgemäßes Warten mit Timeout
            if (System.currentTimeMillis() - startTime > timeout) {
                throw new TimeoutException("Bedingung nicht innerhalb Timeout erfüllt");
            }
            try {
                Thread.sleep(100);  // CPU-Spin vermeiden
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new TimeoutException("Warten unterbrochen");
            }
        }
    }

    // Korrigiert: Finally-Block führt Bereinigung durch
    private Resource resource;

    public void cleanupResources() {
        try {
            resource = allocateResource();
            useResource(resource);
        } finally {
            if (resource != null) {
                try {
                    resource.close();
                } catch (Exception e) {
                    logger.warn("Fehler beim Schließen der Ressource", e);
                }
            }
        }
    }

    // Korrigiert: Absichtlich leerer Block mit Dokumentation
    @SuppressWarnings("EmptyBlock")
    public void optionalCallback(Event event) {
        if (event.getType() == EventType.DEBUG) {
            // Absichtlich in Produktion ignoriert - Debug-Ereignisse sind nur für Entwicklung
            // Siehe Ticket PROJ-1234 für Begründung
        } else {
            processEvent(event);
        }
    }
}
# Korrigiert: Ordnungsgemäße Implementierung in Python
import logging

logger = logging.getLogger(__name__)


class FixedService:

    def validate_credentials(self, username: str, password: str) -> bool:
        """Benutzer-Credentials gegen gespeicherten Hash validieren."""
        if not username or not password:
            logger.warning("Leere Credentials bereitgestellt")
            return False

        user = self._get_user(username)
        if not user:
            logger.warning(f"Benutzer nicht gefunden: {username}")
            return False

        return self._verify_password(password, user.password_hash)

    def process_payment(self, amount: float) -> PaymentResult:
        """Zahlung mit ordnungsgemäßer Fehlerbehandlung verarbeiten."""
        try:
            result = charge_card(amount)
            logger.info(f"Zahlung verarbeitet: {amount}")
            return result

        except PaymentError as e:
            logger.error(f"Zahlung fehlgeschlagen: {e}")
            raise PaymentProcessingError(f"Zahlung von {amount} fehlgeschlagen") from e

        except Exception as e:
            logger.exception("Unerwarteter Zahlungsfehler")
            raise PaymentProcessingError("Zahlungsverarbeitung nicht verfügbar") from e

    def handle_security_event(self, event: SecurityEvent) -> None:
        """Sicherheitsereignisse basierend auf Schweregrad behandeln."""
        if event.severity == 'CRITICAL':
            logger.critical(f"KRITISCHES Sicherheitsereignis: {event}")
            self._alert_security_team(event)
            self._trigger_incident_response(event)

        elif event.severity == 'HIGH':
            logger.error(f"Sicherheitsereignis mit hohem Schweregrad: {event}")
            self._alert_security_team(event)

        else:
            logger.warning(f"Sicherheitsereignis: {event}")
            self._log_security_event(event)

    def acquire_lock(self) -> None:
        """Thread-sichere Aktualisierung mit ordnungsgemäßer Sperrung."""
        with self._lock:
            # Korrigiert: Geschützter Code innerhalb des Context-Managers
            self._shared_data += 1
            self._last_updated = datetime.now()


# Korrigiert: Abstrakte Methode für erforderliche Implementierung
from abc import ABC, abstractmethod


class SecurityHandler(ABC):
    @abstractmethod
    def on_security_event(self, event: SecurityEvent) -> None:
        """Unterklassen Müssen diese Methode implementieren."""
        pass  # Dieses 'pass' ist in Ordnung - es ist abstrakt
// Korrigiert: Ordnungsgemäße Implementierung in C#
public class FixedHandler
{
    private readonly ILogger<FixedHandler> _logger;

    // Korrigiert: Abstrakte Methode erzwingt Implementierung
    public abstract void OnSecurityEvent(SecurityEvent evt);

    // Oder: Implementierte virtuelle Methode mit Standardverhalten
    public virtual void OnSecurityEventWithDefault(SecurityEvent evt)
    {
        _logger.LogWarning("Sicherheitsereignis empfangen: {Event}", evt);
        // Standardbehandlung die Unterklassen erweitern können
    }

    // Korrigiert: Ordnungsgemäße Ausnahmebehandlung
    public void SaveData(object data)
    {
        try
        {
            _database.Save(data);
            _logger.LogInformation("Daten erfolgreich gespeichert");
        }
        catch (SqlException ex)
        {
            _logger.LogError(ex, "Datenbankfehler beim Speichern");
            throw new DataPersistenceException("Speichern der Daten fehlgeschlagen", ex);
        }
    }

    // Korrigiert: Lock-Block enthält geschützten Code
    private readonly object _lockObj = new object();
    private int _value;

    public void UpdateValue(int newValue)
    {
        lock (_lockObj)
        {
            // Korrigiert: Geschützter Code innerhalb lock
            _value = newValue;
            _lastUpdated = DateTime.UtcNow;
        }
    }

    // Korrigiert: Bedingte Blöcke implementiert
    public void ProcessInput(string input)
    {
        if (IsMalicious(input))
        {
            _logger.LogWarning("Bösartige Eingabe blockiert: {Input}", input);
            throw new SecurityException("Bösartige Eingabe erkannt");
        }

        // Nur für nicht-bösartige Eingabe erreicht
        ExecuteCommand(input);
    }
}

CVE-Beispiele

Leere Codeblöcke, insbesondere leere Catch-Blöcke, haben zu zahlreichen Schwachstellen beigetragen, indem sie sicherheitsrelevante Ausnahmen stillschweigend ignorierten. Spezifische CVEs werden jedoch typischerweise auf die resultierende Schwäche abgebildet und nicht direkt auf diese CWE.


Verwandte CWEs

  • CWE-1164: Irrelevant Code (Eltern)
  • CWE-1069: Empty Exception Block (Kind)
  • CWE-390: Detection of Error Condition Without Action (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1071: Empty Code Block." https://cwe.mitre.org/data/definitions/1071.html

  2. SonarSource. "Code Smell: Empty Block."

  3. PMD. "Empty Statement Rules."