Skip to content

Set correct restype for ca_element_count#51

Open
jacquelinegarrahan wants to merge 1 commit into
epics-base:masterfrom
jacquelinegarrahan:fix/ca-element-count-restype
Open

Set correct restype for ca_element_count#51
jacquelinegarrahan wants to merge 1 commit into
epics-base:masterfrom
jacquelinegarrahan:fix/ca-element-count-restype

Conversation

@jacquelinegarrahan

Copy link
Copy Markdown

Set correct restype for ca_element_count

Branch: fix/ca-element-count-restypemaster

Summary

src/python/epicscorelibs/ca/cadef.py declares the ctypes binding for
ca_element_count but never sets its restype:

ca_element_count = libca.ca_element_count
ca_element_count.argtypes = [ctypes.c_void_p]
ca_element_count.errcheck = expect_connected(0)

The C signature (verified in modules/ca/src/client/cadef.h:227) is:

LIBCA_API unsigned long epicsStdCall ca_element_count (chid chan);

With no restype, ctypes defaults to c_int (32-bit signed). On LP64
platforms (Linux/macOS), where unsigned long is 64-bit, a return value that
doesn't fit in a signed 32-bit int is read from only the low 32 bits — giving a
wrong or negative count. If those low 32 bits happen to be zero, the
expect_connected(0) errcheck would additionally raise a spurious
Disconnected.

The sibling binding ca_field_type sets an explicit restype; this one was
simply overlooked.

Fix

Add ca_element_count.restype = ctypes.c_ulong (matching the C unsigned long).

Verification

cadef.py byte-compiles. The truncation is demonstrated independently with a
libc unsigned long function, which reproduces the exact defect and the fix:

default restype (c_int)  -> -1294967296   # unsigned long 3_000_000_000 truncated
restype = c_ulong        ->  3000000000   # correct

Risk

Very low. For the common case of small element counts (< 2^31) behavior is
identical; the fix only changes the previously-wrong result for pathologically
large arrays and removes a latent sign/truncation hazard on 64-bit hosts.

The C signature is "unsigned long ca_element_count(chid)" (cadef.h), but
no restype was declared, so ctypes defaulted to c_int (32-bit signed).
On LP64 platforms (Linux/macOS) an element count that does not fit in a
signed 32-bit int is read from only the low 32 bits, yielding a wrong or
negative count; if those low bits happen to be zero, the expect_connected(0)
errcheck would also falsely raise Disconnected.

Declare restype = ctypes.c_ulong to match the C return type, consistent
with the explicit restype already set on its sibling ca_field_type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant