Fix Moved() null.source_atom crash (#22537)

* Please describe the intent of your changes in a clear fashion.
This PR addresses the runtime error "Cannot read null.source_atom: proc
name: Moved" occurring in `/atom/movable/proc/Moved`.

**Root Cause:**
When a `datum/dynamic_light_source` or `datum/static_light_source` is
deleted (e.g., an item emitting light is removed), BYOND nullifies its
reference in any lists it's part of. If the cleanup in the light
source's `Destroy()` proc is incomplete (e.g., due to `contained_atom`
changing before deletion), a null entry can remain in the
`hybrid_light_sources` or `static_light_sources` lists of the atom it
was attached to (like a mob).

When the atom moves, the `Moved()` proc iterates these lists.
Encountering a null entry and attempting to access `null.source_atom`
results in a crash.

**Solution:**
1. **Null-guard datum references:** Added checks (`if(!light)` and
`if(!L)`) within the `Moved()` proc's loops for `hybrid_light_sources`
and `static_light_sources`.
2. **Prune stale entries:** If a null datum is found, it is immediately
removed from its respective list using `LAZYREMOVE` to prevent future
occurrences and clean up the list.
3. **Null-guard `source_atom`:** Added a secondary check
(`if(!light.source_atom)`) to ensure `source_atom` itself is not null
before attempting to call `update_light()` or `static_update_light()`.

These changes prevent the crash by safely handling null references
during iteration and proactively cleaning up the lists.

* Please make sure that, in the case of mapping changes, you include
images of these changes in the PR's description.
* Please make sure to mark your PR as wip or review required by making a
comment with !wip or !review required
* If you include sprites/sounds/... (assets) that you have not created
yourself specify the license and original author below.
* Ensure that you also credit them in the appropriate location /
changelog as specified in the contributor guidelines

### Asset Licenses
The following assets that **have not** been created by myself are
included in this PR:

| Path | Original Author | License |
| --- | --- | --- |
| icons/example.dmi | ExamplePerson (Example Station) | CC0 |

Fixes SERVER-PROD-GQ

---------

Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
sentry[bot]
2026-06-01 10:35:38 +00:00
committed by GitHub
co-authored by sentry[bot] <39604003+sentry[bot]@users.noreply.github.com> VMSolidus
parent 32fbb7d965
commit 86e01dba16
2 changed files with 13 additions and 1 deletions
+9 -1
View File
@@ -577,11 +577,19 @@
/* END Spatial grid stuffs */
for(var/datum/dynamic_light_source/light as anything in hybrid_light_sources)
if(!light) // datum was deleted but list entry not yet pruned
LAZYREMOVE(hybrid_light_sources, light)
continue
if(!light.source_atom)
continue
light.source_atom.update_light()
if(!isturf(loc))
light.find_containing_atom()
for(var/datum/static_light_source/L as anything in static_light_sources) // Cycle through the light sources on this atom and tell them to update.
L.source_atom.static_update_light()
if(!L) // datum was deleted but list entry not yet pruned
LAZYREMOVE(static_light_sources, L)
continue
L.source_atom?.static_update_light()
/atom/movable/Exited(atom/movable/gone, direction)
. = ..()
@@ -0,0 +1,4 @@
author: Hellfirejag
delete-after: True
changes:
- bugfix: "Fixed a runtime regularly caused by flashlights."