Skip to content

[CLIENT-4845] Fix user dictionary returning only the first entry of read_info and write_info array of integers#1074

Merged
juliannguyen4 merged 36 commits into
devfrom
CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints
Jun 3, 2026
Merged

[CLIENT-4845] Fix user dictionary returning only the first entry of read_info and write_info array of integers#1074
juliannguyen4 merged 36 commits into
devfrom
CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints

Conversation

@juliannguyen4
Copy link
Copy Markdown
Collaborator

@juliannguyen4 juliannguyen4 commented May 21, 2026

https://aerospike-python-client.readthedocs.io/en/latest/client.html#user-dictionary

Tests for admin_query_user_info() and admin_query_users_info() were not checking the user dictionary correctly. Now these tests match the documentation

Extra changes

  • Tests for client.admin_query_user_info() and client.admin_query_users_info(): when checking the roles in the user dictionary, only check the presence of the roles and they shouldn't be in a particular order.

Manual testing

  • Build artifacts passes. Workflow run
  • Valgrind shows no memory errors or leaks
  • Massif usage looks ok
  • Code coverage looks good. (70% coverage because the untested lines are only when the C-Python API calls fail, which is unlikely to happen)

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 21, 2026

Codecov Report

❌ Patch coverage is 70.31250% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.46%. Comparing base (dcb61cb) to head (dd94e56).
⚠️ Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
src/main/conversions.c 70.31% 19 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #1074      +/-   ##
==========================================
+ Coverage   84.44%   84.46%   +0.02%     
==========================================
  Files          99       99              
  Lines       14062    14088      +26     
==========================================
+ Hits        11874    11899      +25     
- Misses       2188     2189       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@juliannguyen4 juliannguyen4 changed the base branch from dev to CLIENT-4868-cicd-fix-regression-where-smoke-tests-no-longer-builds-python-client-with-Werror May 29, 2026 16:28
@juliannguyen4 juliannguyen4 force-pushed the CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints branch from f5e6601 to a2cf9e3 Compare May 29, 2026 16:29
…nger-builds-python-client-with-Werror' into CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints
@juliannguyen4 juliannguyen4 force-pushed the CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints branch from 00169e6 to 9a17540 Compare May 29, 2026 16:42
…believe using void** parameter is dangerous because to accept an array of ints, we would need to cast void* to int which can be dangerous where int is only 32-bit like on windows
@juliannguyen4 juliannguyen4 force-pushed the CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints branch from 4132f6a to 4e7fcdb Compare May 29, 2026 20:23
Base automatically changed from CLIENT-4868-cicd-fix-regression-where-smoke-tests-no-longer-builds-python-client-with-Werror to dev June 1, 2026 14:56
@juliannguyen4 juliannguyen4 marked this pull request as ready for review June 2, 2026 23:26
Comment thread src/main/conversions.c
char format_str[2];
sprintf(format_str, "%c", format_specifier);
switch (format_specifier) {
case 'k': {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI picked this up, looks like it is worth using I here.

Py_BuildValue format 'k' doesn't match the uint32_t argument

In convert_nullable_array_to_py_optional_list:

case 'k': {
uint32_t element = ((uint32_t *)array)[i];
py_element = Py_BuildValue(format_str, element); // format_str == "k"
break;
}

read_info and write_info are uint32_t* (confirmed in as_admin.h: uint32_t* read_info;, uint32_t* write_info;), and uint32_t is unsigned
int on all target platforms. But the 'k' format code tells Py_BuildValue to read an unsigned long via va_arg.

This is a varargs type mismatch (undefined behavior):

  • Windows (LLP64): unsigned long is 32-bit → happens to match, fine.
  • Linux/macOS x86-64 (LP64): unsigned long is 64-bit. The 32-bit unsigned int is passed in a register that the compiler typically
    zero-extends, so it usually works by luck — but it's relying on UB.
  • aarch64 (LP64): unsigned long is also 64-bit. The AAPCS64 ABI does not guarantee the upper 32 bits of a narrow variadic slot are
    zeroed, so va_arg(ap, unsigned long) can read garbage in the high word → wrong read_info/write_info integers. They build and ship aarch64
    wheels, so this is a genuine cross-platform correctness risk, not purely theoretical.

Fix: use the 'I' (unsigned int) format code for uint32_t:

case 'I': {
uint32_t element = ((uint32_t *)array)[i];
py_element = Py_BuildValue(format_str, element);
break;
}
(and pass 'I' instead of 'k' from as_user_info_to_pyobject). Alternatively keep 'k' but cast the argument: Py_BuildValue("k", (unsigned
long)element). The 'I' change is cleaner. Note their valgrind/CI run on x86-64 will not catch this because of the incidental
zero-extension.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's safe to use I (unsigned int) as the format specifier since it's only guaranteed to be at least 2 bytes large. In theory if unsigned int was 2 bytes large, I think passing in an unsigned 32-bit integer value to I would cause the value to be truncated or cause undefined behavior.

unsigned long is always at least 32 bits long, so I think the unsigned long cast is not needed; unsigned long can always accomodate a uint32_t value.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed on the I point. I think the problem is when k causes Py_BuildValue to read 64 bits where element is only a 32 bit unsigned int that isn't promoted because Py_BuildValue uses variadic arguments. I think Py_BuildValue("k", (unsigned long)element); would make this safe. Let me know what you think.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll make that change

Copy link
Copy Markdown
Contributor

@dwelch-spike dwelch-spike left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@juliannguyen4
Copy link
Copy Markdown
Collaborator Author

juliannguyen4 commented Jun 3, 2026

Noticed one failing test case related to bin projection on macos x86. test_query_nested_results in TestQueryBinProjection is not returning enough records from query.results(). I haven't seen this result before

Wasn't able to get any meaningful server logs:

gh run view --log --job 79400892054 | cut -f 3- | grep WARNING | grep -i -e query -e scan

These changes aren't related to bin projection, but I'll just rerun the bin projection tests on macos x86 a few times to see how reproducible it is. If I can't reproduce the error then I'll merge this

EDIT - Reran the bin projection tests on macos x86 two times, and they all pass.

https://github.com/aerospike/aerospike-client-python/actions/runs/26918869948
https://github.com/aerospike/aerospike-client-python/actions/runs/26918865636

TODO - need to log a Jira ticket w/ workflow run

@juliannguyen4 juliannguyen4 merged commit 5bc339b into dev Jun 3, 2026
156 of 158 checks passed
@juliannguyen4 juliannguyen4 deleted the CLIENT-4845-fix-user-dictionary-only-returning-integers-instead-of-list-of-ints branch June 3, 2026 23:30
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.

3 participants