diff --git a/docs/api/errors.md b/docs/api/errors.md
index 6084023..8ad21d9 100644
--- a/docs/api/errors.md
+++ b/docs/api/errors.md
@@ -18,6 +18,7 @@ except PyMemoryEditorError as exc:
```text
Exception
└── PyMemoryEditorError
+ ├── BitnessDetectionError
├── ClosedProcess
├── ProcessIDNotExistsError
├── ProcessNotFoundError
@@ -112,6 +113,36 @@ except AmbiguousProcessNameError as exc:
process = OpenProcess(pid=exc.pids[0])
```
+### `BitnessDetectionError`
+
+Raised when `strict_bitness=True` and the target's 32-/64-bit width could
+not be read from its own headers (the ELF class on Linux, the Mach-O magic
+on macOS, `IsWow64Process` on Windows).
+
+Without strict mode the library falls back to the host word size — a guess
+that may silently produce wrong pointer-width defaults.
+
+```{eval-rst}
+.. py:exception:: BitnessDetectionError
+
+ .. py:attribute:: pid
+ :type: int
+
+ The PID whose bitness could not be determined.
+```
+
+Example:
+
+```python
+from PyMemoryEditor import OpenProcess, BitnessDetectionError
+
+try:
+ with OpenProcess(pid=1234, strict_bitness=True) as process:
+ print(process.is_64bit)
+except BitnessDetectionError as exc:
+ print(f"Could not detect bitness of PID {exc.pid}")
+```
+
## Standard exceptions
diff --git a/docs/api/openprocess.md b/docs/api/openprocess.md
index 32a2169..c6796f0 100644
--- a/docs/api/openprocess.md
+++ b/docs/api/openprocess.md
@@ -23,7 +23,7 @@ All three subclass `AbstractProcess` and share the API documented below.
## Construction
```{eval-rst}
-.. py:class:: OpenProcess(*, name=None, pid=None, permission=, case_sensitive=, exact_match=True)
+.. py:class:: OpenProcess(*, name=None, pid=None, permission=, case_sensitive=, exact_match=True, strict_bitness=False)
Open a target process. ``OpenProcess`` resolves to the concrete backend for
the host OS, so the ``permission`` and ``case_sensitive`` defaults are
@@ -44,6 +44,11 @@ All three subclass `AbstractProcess` and share the API documented below.
ignores case. Default is ``False`` on Windows, ``True`` elsewhere.
:param bool exact_match: when ``False``, ``name`` matches as a
substring (``"chrome"`` matches ``"chrome.exe"``).
+ :param bool strict_bitness: when ``True``, :py:attr:`is_64bit` raises
+ :py:exc:`BitnessDetectionError` if the target's 32-/64-bit width
+ can't be read from its headers, instead of falling back to the host
+ word size. Use it when a wrong pointer-width default would be worse
+ than a hard failure.
:raises ProcessNotFoundError: no process matches ``name``.
:raises ProcessIDNotExistsError: ``pid`` doesn't exist.
@@ -92,6 +97,33 @@ with OpenProcess(
The conventional "main thread" of the target — by convention, the thread
with the smallest ``tid``. Returns ``None`` if the process has no listable
threads (rare).
+
+.. py:attribute:: is_64bit
+ :type: bool
+
+ ``True`` if the target process is 64-bit, ``False`` if it is 32-bit.
+ Detected once on first access (via headers: ELF class on Linux, Mach-O
+ magic on macOS, ``IsWow64Process`` on Windows) and cached.
+
+ When the backend can't read the headers, the result depends on
+ ``strict_bitness``: ``False`` (default) falls back to the host word size
+ and logs a WARNING; ``True`` raises
+ :py:exc:`BitnessDetectionError`.
+
+.. py:attribute:: is_bitness_certain
+ :type: bool
+
+ ``True`` if :py:attr:`is_64bit` was read from the target's own headers,
+ ``False`` if it fell back to a guess of the host word size.
+
+ When ``False`` the automatic ``ptr_size`` default may be wrong for a
+ cross-bitness target — pass ``ptr_size`` explicitly to the pointer APIs.
+
+.. py:attribute:: pointer_size
+ :type: int
+
+ Pointer width of the target process in bytes — ``8`` for a 64-bit target,
+ ``4`` for a 32-bit one. Derived from :py:attr:`is_64bit`.
```
## Methods