Add safeguards to share_many_airs and gas_mixture (#30077)

* Add safeguards to `share_many_airs`

* More safeguards!

* Crash out of HE pipe heat transfer if transfer value is not sane.
This commit is contained in:
Charlie Nolan
2025-09-16 17:49:19 +00:00
committed by GitHub
parent ef5f1caafa
commit b2f3eac474
3 changed files with 66 additions and 10 deletions
+3
View File
@@ -254,3 +254,6 @@
/// Returns the hex value of a decimal number. len == length of returned string.
#define num2hex(X, len) uppertext(num2text(X, len, 16))
/// Tests if the value is in the given range.
#define IS_IN_BOUNDS(val, lower, upper) ((val) >= (lower) && (val) <= (upper))
@@ -58,43 +58,78 @@ What are the archived variables for?
return private_oxygen
/datum/gas_mixture/proc/set_oxygen(value)
private_oxygen = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_oxygen = clamped
/datum/gas_mixture/proc/carbon_dioxide()
return private_carbon_dioxide
/datum/gas_mixture/proc/set_carbon_dioxide(value)
private_carbon_dioxide = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_carbon_dioxide = clamped
/datum/gas_mixture/proc/nitrogen()
return private_nitrogen
/datum/gas_mixture/proc/set_nitrogen(value)
private_nitrogen = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_nitrogen = clamped
/datum/gas_mixture/proc/toxins()
return private_toxins
/datum/gas_mixture/proc/set_toxins(value)
private_toxins = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_toxins = clamped
/datum/gas_mixture/proc/sleeping_agent()
return private_sleeping_agent
/datum/gas_mixture/proc/set_sleeping_agent(value)
private_sleeping_agent = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_sleeping_agent = clamped
/datum/gas_mixture/proc/agent_b()
return private_agent_b
/datum/gas_mixture/proc/set_agent_b(value)
private_agent_b = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_agent_b = clamped
/datum/gas_mixture/proc/temperature()
return private_temperature
/datum/gas_mixture/proc/set_temperature(value)
private_temperature = value
if(isnan(value) || !isnum(value))
CRASH("Bad value: [value]")
var/clamped = clamp(value, 0, 1e10)
if(value != clamped)
stack_trace("Out-of-bounds value [value] clamped to [clamped].")
private_temperature = clamped
/datum/gas_mixture/proc/hotspot_temperature()
return private_hotspot_temperature
@@ -662,7 +697,7 @@ What are the archived variables for?
private_hotspot_volume = milla[MILLA_INDEX_HOTSPOT_VOLUME]
private_fuel_burnt = milla[MILLA_INDEX_FUEL_BURNT]
/proc/share_many_airs(list/mixtures)
/proc/share_many_airs(list/mixtures, atom/root)
var/total_volume = 0
var/total_oxygen = 0
var/total_nitrogen = 0
@@ -691,9 +726,12 @@ What are the archived variables for?
total_sleeping_agent += G.private_sleeping_agent
total_agent_b += G.private_agent_b
if(total_volume <= 0)
if(total_volume == 0)
return
if(total_volume < 0 || isnan(total_volume) || !isnum(total_volume) || total_oxygen < 0 || isnan(total_oxygen) || !isnum(total_oxygen) || total_nitrogen < 0 || isnan(total_nitrogen) || !isnum(total_nitrogen) || total_toxins < 0 || isnan(total_toxins) || !isnum(total_toxins) || total_carbon_dioxide < 0 || isnan(total_carbon_dioxide) || !isnum(total_carbon_dioxide) || total_sleeping_agent < 0 || isnan(total_sleeping_agent) || !isnum(total_sleeping_agent) || total_agent_b < 0 || isnan(total_agent_b) || !isnum(total_agent_b))
CRASH("A pipenet with [length(mixtures)] connected airs is corrupt and cannot flow safely. Pipenet root is [root] at ([root.x], [root.y], [root.z]).")
// If we don't have a significant temperature difference, check for a significant gas amount difference.
if(!must_share)
for(var/datum/gas_mixture/G in mixtures)
@@ -737,6 +775,9 @@ What are the archived variables for?
if(total_heat_capacity > 0)
temperature = total_thermal_energy/total_heat_capacity
if(temperature <= 0 || isnan(temperature) || !isnum(temperature))
CRASH("A pipenet with [length(mixtures)] connected airs is corrupt and cannot flow safely. Pipenet root is [root] at ([root.x], [root.y], [root.z]).")
// Update individual gas_mixtures by volume ratio.
for(var/datum/gas_mixture/G in mixtures)
if(QDELETED(G))
@@ -160,6 +160,9 @@
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
if(!IS_IN_BOUNDS(heat, -1e10, 1e10))
CRASH("Sharing [partial_heat_capacity] @ [pipeline.air.temperature()]K with solid-wall environment [modeled_location.heat_capacity] @ [modeled_location.temperature]K produced out-of-bounds heat transfer [heat]!")
pipeline.air.set_temperature(pipeline.air.temperature() - heat / total_heat_capacity)
modeled_location.temperature += heat/modeled_location.heat_capacity
@@ -179,6 +182,9 @@
self_temperature_delta = -heat/total_heat_capacity
sharer_temperature_delta = heat/sharer_heat_capacity
if(!IS_IN_BOUNDS(heat, -1e10, 1e10))
CRASH("Sharing [partial_heat_capacity] @ [pipeline.air.temperature()]K with environment [sharer_heat_capacity] @ [environment.temperature()]K produced out-of-bounds heat transfer [heat]!")
else
return 1
@@ -194,6 +200,8 @@
var/heat = thermal_conductivity * delta_temperature * \
(partial_heat_capacity * target.heat_capacity / (partial_heat_capacity + target.heat_capacity))
if(!IS_IN_BOUNDS(heat, -1e10, 1e10))
CRASH("Sharing [partial_heat_capacity] @ [pipeline.air.temperature()]K with static environment [target.heat_capacity] @ [target.temperature]K produced out-of-bounds heat transfer [heat]!")
pipeline.air.set_temperature(pipeline.air.temperature() - heat / total_heat_capacity)
pipeline.update = TRUE
@@ -232,7 +240,11 @@
if(C.connected_device)
GL += C.portableConnectorReturnAir()
share_many_airs(GL)
if(length(members))
share_many_airs(GL, members[1])
else if(length(other_atmosmch))
share_many_airs(GL, other_atmosmch[1])
// If neither has anything, GL will have no volumen, so nothing to share.
/datum/pipeline/proc/add_ventcrawler(mob/living/crawler)
if(!(crawler in crawlers))