gcode_macro: Use deepcopy() on get_status() results

If a get_status() method returns a mutable object (such as a list or
dict) then it would be possible for a gcode command template to
incorrectly alter the program's internal state.  Perform a deepcopy()
operation on all get_status() return results to avoid that.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-01-14 22:13:50 -05:00
parent 5b9beb52f6
commit 023a985bfc
4 changed files with 8 additions and 9 deletions

View File

@ -1,9 +1,9 @@
# Add ability to define custom g-code macros # Add ability to define custom g-code macros
# #
# Copyright (C) 2018-2019 Kevin O'Connor <kevin@koconnor.net> # Copyright (C) 2018-2021 Kevin O'Connor <kevin@koconnor.net>
# #
# This file may be distributed under the terms of the GNU GPLv3 license. # This file may be distributed under the terms of the GNU GPLv3 license.
import traceback, logging, ast import traceback, logging, ast, copy
import jinja2 import jinja2
@ -26,7 +26,7 @@ class GetStatusWrapper:
raise KeyError(val) raise KeyError(val)
if self.eventtime is None: if self.eventtime is None:
self.eventtime = self.printer.get_reactor().monotonic() self.eventtime = self.printer.get_reactor().monotonic()
self.cache[sval] = res = dict(po.get_status(self.eventtime)) self.cache[sval] = res = copy.deepcopy(po.get_status(self.eventtime))
return res return res
def __contains__(self, val): def __contains__(self, val):
try: try:
@ -157,9 +157,8 @@ class GCodeMacro:
pdesc = "Renamed builtin of '%s'" % (self.alias,) pdesc = "Renamed builtin of '%s'" % (self.alias,)
self.gcode.register_command(self.rename_existing, prev_cmd, desc=pdesc) self.gcode.register_command(self.rename_existing, prev_cmd, desc=pdesc)
self.gcode.register_command(self.alias, self.cmd, desc=self.cmd_desc) self.gcode.register_command(self.alias, self.cmd, desc=self.cmd_desc)
return dict(self.variables)
def get_status(self, eventtime): def get_status(self, eventtime):
return dict(self.variables) return self.variables
cmd_SET_GCODE_VARIABLE_help = "Set the value of a G-Code macro variable" cmd_SET_GCODE_VARIABLE_help = "Set the value of a G-Code macro variable"
def cmd_SET_GCODE_VARIABLE(self, gcmd): def cmd_SET_GCODE_VARIABLE(self, gcmd):
variable = gcmd.get('VARIABLE') variable = gcmd.get('VARIABLE')

View File

@ -284,8 +284,8 @@ class PrinterHeaters:
"G-Code sensor id %s already registered" % (gcode_id,)) "G-Code sensor id %s already registered" % (gcode_id,))
self.gcode_id_to_sensor[gcode_id] = psensor self.gcode_id_to_sensor[gcode_id] = psensor
def get_status(self, eventtime): def get_status(self, eventtime):
return {'available_heaters': list(self.available_heaters), return {'available_heaters': self.available_heaters,
'available_sensors': list(self.available_sensors)} 'available_sensors': self.available_sensors}
def turn_off_all_heaters(self, print_time=0.): def turn_off_all_heaters(self, print_time=0.):
for heater in self.heaters.values(): for heater in self.heaters.values():
heater.set_temp(0.) heater.set_temp(0.)

View File

@ -8,7 +8,7 @@ class QueryEndstops:
def __init__(self, config): def __init__(self, config):
self.printer = config.get_printer() self.printer = config.get_printer()
self.endstops = [] self.endstops = []
self.last_state = {} self.last_state = []
# Register webhook if server is available # Register webhook if server is available
webhooks = self.printer.lookup_object('webhooks') webhooks = self.printer.lookup_object('webhooks')
webhooks.register_endpoint( webhooks.register_endpoint(

View File

@ -57,7 +57,7 @@ class SaveVariables:
gcmd.respond_info("Variable Saved") gcmd.respond_info("Variable Saved")
self.loadVariables() self.loadVariables()
def get_status(self, eventtime): def get_status(self, eventtime):
return {'variables': dict(self.allVariables)} return {'variables': self.allVariables}
def load_config(config): def load_config(config):
return SaveVariables(config) return SaveVariables(config)