From 654fa20dbe8b35bf5d8f7b96530bb90e321fe15f Mon Sep 17 00:00:00 2001 From: ppannuto-claude Date: Tue, 1 Sep 2026 12:11:25 -0700 Subject: [PATCH] tockloader: fix address-truthiness bugs around a valid 0x0 Several places in the codebase distinguish "no address given/known" from "an address was given/known" using plain truthiness (`if addr:`) on a value that is `None` when unset. That conflates "unset" with an address of exactly `0x0`, which is a normal, valid flash and/or app base address (e.g. any Cortex-M board, or Tock's qemu_arm_mps2 boards). Fix all of these to check `is not None` instead: - `main.py` `command_local_board_set()`: an explicit `--app-address 0x0`/`--flash-address 0x0` was validated but then silently omitted from the status output, making it look like the flag was ignored. - `flash_file.py` `set_local_board()`: the same values were then silently dropped from the persisted `local-board` TOML config, discarding the deliberate setting entirely. - `flash_file.py` `FlashFile.get_flash_address()`: a stored `flash_address == 0` was reported as `None` (unknown) instead of `0`. - `board_interface.py` `BoardInterface.get_apps_start_address()`: a configured `app_address == 0` was ignored in favor of querying the board's `appaddr` attribute (or returning `None` if that's absent). - `tockloader.py` `_get_apps_start_address()`: a cached value of `0`, an explicit `--app-address 0x0` on any command (not just `local-board set`), or a channel-reported address of `0` were all treated as "unknown" and silently overridden by lower-priority defaults. - `tockloader.py` `_get_flash_start_address()`: a channel-reported flash address of `0` was treated as "unknown" and replaced with the function's own hardcoded `0` default -- harmless today only because that default happens to also be `0`. - `tockloader.py` `_get_memory_start_address()`: same cached-value pattern as above, for the app RAM start address. Verified with `local-board set zerotest --arch cortex-m3 --app-address 0x0 --flash-address 0x0`: both values now appear in the status output and are correctly persisted as `0` (not omitted) in the TOML config. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01KTQ6pWrckM3jp9vfBo4bhk --- tockloader/board_interface.py | 2 +- tockloader/flash_file.py | 6 +++--- tockloader/main.py | 4 ++-- tockloader/tockloader.py | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tockloader/board_interface.py b/tockloader/board_interface.py index 4558e27..1488265 100644 --- a/tockloader/board_interface.py +++ b/tockloader/board_interface.py @@ -563,7 +563,7 @@ def get_apps_start_address(self): """ Return the address in flash where apps start. """ - if hasattr(self, "app_address") and self.app_address: + if hasattr(self, "app_address") and self.app_address is not None: return self.app_address else: attributes = self.get_all_attributes() diff --git a/tockloader/flash_file.py b/tockloader/flash_file.py index 81bb019..1811cb2 100644 --- a/tockloader/flash_file.py +++ b/tockloader/flash_file.py @@ -120,7 +120,7 @@ def translate_address(self, address): return address - flash_address def get_flash_address(self): - if hasattr(self, "flash_address") and self.flash_address: + if hasattr(self, "flash_address") and self.flash_address is not None: return self.flash_address return None @@ -216,9 +216,9 @@ def set_local_board( local_board = {"board": board, "filepath": filepath} if arch: local_board["arch"] = arch - if app_address: + if app_address is not None: local_board["app_address"] = app_address - if flash_address: + if flash_address is not None: local_board["flash_address"] = flash_address if flush_command: local_board["flush_command"] = flush_command diff --git a/tockloader/main.py b/tockloader/main.py index 3714f01..2989427 100644 --- a/tockloader/main.py +++ b/tockloader/main.py @@ -467,9 +467,9 @@ def command_local_board_set(args): logging.status(f"Setting the default local board to '{board_name}'") if args.arch: logging.status(f" Using arch {args.arch}") - if args.app_address: + if args.app_address is not None: logging.status(f" Using app_address {args.app_address:#02x}") - if args.flash_address: + if args.flash_address is not None: logging.status(f" Using flash_address {args.flash_address:#02x}") if args.flush_command: logging.status(f' Using flush_command "{args.flush_command}"') diff --git a/tockloader/tockloader.py b/tockloader/tockloader.py index 5c1a946..082f827 100644 --- a/tockloader/tockloader.py +++ b/tockloader/tockloader.py @@ -1098,20 +1098,20 @@ def _get_apps_start_address(self): # have a good way to mark it as unset since # app_settings['start_address'] is set by default. cached = getattr(self, "apps_start_address", None) - if cached: + if cached is not None: return cached # Highest priority is the command line argument. If the user specifies # that, we use that unconditionally. cmdline_app_address = getattr(self.args, "app_address", None) - if cmdline_app_address: + if cmdline_app_address is not None: self.apps_start_address = cmdline_app_address return cmdline_app_address # Next we check if the attached board can tell us. if self.channel: channel_apps_start_address = self.channel.get_apps_start_address() - if channel_apps_start_address: + if channel_apps_start_address is not None: self.apps_start_address = channel_apps_start_address return channel_apps_start_address @@ -1127,7 +1127,7 @@ def _get_flash_start_address(self): # Check if the attached board can tell us. if self.channel: channel_flash_address = self.channel.get_flash_address() - if channel_flash_address: + if channel_flash_address is not None: return channel_flash_address # In the default case flash starts at address 0. @@ -1143,7 +1143,7 @@ def _get_memory_start_address(self): # app RAM address often, so we don't want to have to query the board for # it each time. cached = getattr(self, "app_ram_address", None) - if cached: + if cached is not None: return cached # Next we check for kernel attributes.