Skip to content

swig: guard against silent attribute typos on SWIG objects#3300

Merged
igaw merged 1 commit intolinux-nvme:masterfrom
martin-belanger:setattr-guard
Apr 21, 2026
Merged

swig: guard against silent attribute typos on SWIG objects#3300
igaw merged 1 commit intolinux-nvme:masterfrom
martin-belanger:setattr-guard

Conversation

@martin-belanger
Copy link
Copy Markdown

Problem

SWIG-generated Python classes allow assigning arbitrary attributes on instances. A caller writing:

ctrl.dhchap_key = x        # typo — correct name is dhchap_ctrl_key

silently creates a new Python instance attribute instead of calling the C-level property setter. The value is discarded and the bug is invisible at runtime. This has already caused a real bug in nvme-stas where dhchap_key was written instead of dhchap_ctrl_key, meaning the controller DHCHAP key was never actually set. What actually happened is that the property dhchap_key had been renamed to dhchap_ctrl_key in libnvme's python bindings, but had not been changed in nvme-stas causing a silent failure.

The same silent-failure applies to the ctrl constructor dict: a typo in a key such as subsysnqn_typo was previously ignored without error.

Changes

libnvme/libnvme/nvme.i

Add a __setattr__ guard (via %pythoncode) to four classes:
libnvme_global_ctx, libnvme_host, libnvme_subsystem, and libnvme_ctrl.

The guard:

  • Passes through this (SWIG's raw C pointer) and _-prefixed names (GC-anchoring refs set by %pythonappend blocks such as self.__host) via object.__setattr__, bypassing property lookup.
  • Walks the MRO to find a property with an fset and calls it directly, equivalent to Python's default machinery but without allowing fallback to instance-dict creation.
  • Raises AttributeError for everything else — covering both unknown names and %immutable properties (which have no fset).

Note: thisown has an fset, so it is handled correctly by the MRO walk without any special case.

In set_fctx_from_dict(), replace the silent fall-through at the end of the key-dispatch while loop with a PyErr_Format(PyExc_KeyError) - return -1. Every known key already hits continue; any key that falls through is therefore unknown. This avoids a second pass over the dict.

libnvme/libnvme/tests/test-setattr.py (new file)

Six test cases:

  • Valid writable property assignment does not raise.
  • Typo on a property name raises AttributeError immediately.
  • Assignment to a %immutable (read-only) property raises AttributeError.
  • Completely unknown attribute name raises AttributeError.
  • Unknown key in the constructor dict raises KeyError.
  • Missing required key (subsysnqn or transport) raises KeyError.

Testing

meson test -C .build

Comment thread libnvme/libnvme/tests/test-setattr.py
Add __setattr__ to libnvme_global_ctx, libnvme_host,
libnvme_subsystem, and libnvme_ctrl. Without this guard, a caller
writing e.g. ctrl.dhchap_key = x (a typo for dhchap_ctrl_key) would
silently create a new Python instance attribute and discard the value
instead of calling the C-level property setter. This has already caused
a real bug in nvme-stas.

The guard passes through 'this' and '_'-prefixed names (SWIG internals
and GC-anchoring refs set by %pythonappend blocks), walks the MRO to
invoke writable property setters, and raises AttributeError for
everything else — covering both unknown names and %immutable properties.

Also reject unknown keys in the ctrl constructor dict. Previously a
typo in a dict key (e.g. 'subsysnqn_typo') was silently ignored. Now
any unrecognised key raises KeyError at the end of the existing dispatch
loop, with no second pass over the dict.

Add tests/test-setattr.py to cover: valid writable property, typo,
read-only property, unknown attribute, unknown dict key, and missing
required dict key.

Signed-off-by: Martin Belanger <[email protected]>
Assisted-by: Claude Sonnet 4.6 <[email protected]>
@igaw igaw merged commit ed9fefe into linux-nvme:master Apr 21, 2026
28 of 29 checks passed
@igaw
Copy link
Copy Markdown
Collaborator

igaw commented Apr 21, 2026

Thanks!

@martin-belanger martin-belanger deleted the setattr-guard branch April 21, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants