From 74aa74674bd95b5b40b209ca622c98466daaa6de Mon Sep 17 00:00:00 2001 From: ppannuto-claude Date: Tue, 1 Sep 2026 12:11:25 -0700 Subject: [PATCH 1/2] 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. From 04f4a464e43c9b2e83b9f7756aea719b40724e07 Mon Sep 17 00:00:00 2001 From: autoblack Date: Tue, 1 Sep 2026 19:16:56 +0000 Subject: [PATCH 2/2] fixup: Format Python code with Black --- tockloader/app_padding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tockloader/app_padding.py b/tockloader/app_padding.py index 5606d9a..07b0da9 100644 --- a/tockloader/app_padding.py +++ b/tockloader/app_padding.py @@ -73,7 +73,7 @@ def get_binary(self, address=None): tbfh_binary = self.tbfh.get_binary() # Calculate the padding length. padding_binary_size = self.get_size() - len(tbfh_binary) - return tbfh_binary + b"\xFF" * padding_binary_size + return tbfh_binary + b"\xff" * padding_binary_size def info(self, verbose=False): """