module Lapis::Docs::E_MEMORY_SAFETY_AND_ENGINE_INTERNALS::B_DEAD_POINTER_PROTECTION

Overview

Dead-Pointer Protection & Access Violation Defense

Comprehensive guide to Lapis's active dead-pointer protection mechanism, preventing segmentation faults (ACCESS_VIOLATION / 0xC0000005) when nodes are freed by GDScript or the engine.

Executive Summary & Key Topics

Topic Method / Anchor Description
Dead-Pointer Defense Primitives .topic_00_defense_primitives Methods available on every Godot::Object wrapper for defensive lifetime inspection.
The Dead-Pointer Hazard .topic_01_the_segfault_problem How standard bindings crash without stack traces and how Lapis defends against it.
Defensive Coding Patterns .topic_02_defensive_coding_patterns Checking #alive? when holding references to transient entities.

Related Guides & Source References

Defined in:

libgodot/docs/e_memory_safety_and_engine_internals/b_dead_pointer_protection.cr

Class Method Summary

Class Method Detail

def self.topic_00_defense_primitives : Nil #

Dead-Pointer Defense Primitives: Methods available on every Godot::Object wrapper for defensive lifetime inspection.

Key Topics & Information

  • object.alive? : Returns true if native C++ engine object is still valid
  • object.destroyed? : Returns true if node was freed in GDScript or Godot
  • object.check_alive! : Raises Godot::DisposedObjectError if freed

def self.topic_01_the_segfault_problem : Nil #

The Dead-Pointer Hazard: How standard bindings crash without stack traces and how Lapis defends against it.

If an entity (e.g. an enemy) is deleted in GDScript via queue_free(), standard C bindings retain a dangling raw pointer. Dereferencing this pointer triggers an immediate unrecoverable crash: ACCESS_VIOLATION (0xC0000005)

In Lapis, every virtual dispatch and reflection call invokes #check_alive!:

def check_alive! : Void
  return if @pointer.null?
  unless Bridge.is_instance_id_valid(@instance_id)
    @pointer = Pointer(Void).null
    raise Godot::DisposedObjectError.new("Cannot access disposed Godot object")
  end
end

Instead of crashing the game, you get a clean, catchable Crystal exception with full stack trace!


def self.topic_02_defensive_coding_patterns : Nil #

Defensive Coding Patterns: Checking #alive? when holding references to transient entities.

node Tower < Node2D do
  @target : Enemy? = nil

  def _physics_process(delta : Float64) : Void
    # Check alive before firing:
    if enemy = @target
      if enemy.alive?
        fire_at(enemy.global_position)
      else
        @target = nil # Clear stale reference
      end
    end
  end
end