-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
src: Fix incorrect use of cpu_set_t #122
base: master
Are you sure you want to change the base?
src: Fix incorrect use of cpu_set_t #122
Conversation
36fc52d
to
6deeec4
Compare
As we have: |
That's not the only place where a cpuset is created: Currently, rt-app with musl libc crashes with a given input and when the JSON file name (as passed to CLI) is larger than 92 chars. The crash happens inside CPU_EQUAL_S, where it can be seen that the size that the libc is assuming differs from what is in the In the details, the musl libc defines:
So a cpu_set_t is 128 bytes long. When we use the dynamic allocation API, we end up with a much smaller object. The fixed-size API ends up using memcmp on with size=128 whereas the value are smaller, so it ends up reading garbage (and unmapped area when the stars are aligned). |
Actually it's not the end of the troubles, the patch fixes the crash but now I end up with things like:
I spotted the following remaining problems:
Even though the man page specifies:
On top of that there is no guarantee that sizeof(cpu_set_t) is higher or equal than
Given that the code to retrieve the affinity is:
there is no way we will ever get a CPU ID higher than what fits in a fixed-sized cpu_set_t, so I'm wondering:
|
6deeec4
to
4d0618c
Compare
Updated with a corrected call to CPU_SET_S (arguments were swapped) and a commit to use the fixed-size API instead of the variably-sized API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
@vingu-linaro I'm considering if it is appropriate for me to merge these changes - they look good to me, we need them because our clib triggers the issue, and we've been using them for a while now. Would you have any objection to me hitting the big green button? Thanks! |
@credp Let me try to remember what was the open question for this PR |
patch 1 says: cpu_set_t allocated dynamically with CPU_ALLOC need to be manipulated So should we remove patch1 and only keeps patch2 ? |
I think the reason I removed
So there is no point in using the dynamic size API in the current state of the code, since by construction we will never get a With both patches, you end up with client code that does not care about what specific type of cpu set is being used. If you drop the first patch, you also drop the ability to easily switch back to a dynamically allocated cpu set (I suppose another API than pthread allows getting the cpu count no matter how big). And that would amount to shooting yourself in the foot: Currently, rt-app will fail to handle more than 128 CPUs in proper static builds, so I wouldn't drop the code that will allow fixing that easily. |
But all this is quite misleading: |
if (!CPU_EQUAL(actual_cpu_data->cpuset, data->curr_cpu_data->cpuset)) | ||
{ | ||
if ( | ||
actual_cpu_data->cpusetsize != data->curr_cpu_data->cpusetsize || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Witht this PR, cpusetsize is always set to sizeof(cpu_set_t) so this test is useless
I fix the current segfault, make the code agree with itself (I did not introduce |
I'm not saying the PR is irrelevant, I'm saying that patch 1 is irrelevant because patch 2 removes the code that patch1 wants to fix so patch 1 is useless. That's why I asked you to keep patch 2 and remove patch 1 |
Updated the PR with an extra couple of patches to make the max number of detected CPUs configurable. Note that these 2 patches are entirely untested. |
Tested the branch in its current state including the last 2 patches, they build and seem to work fine:
|
for (i = 0; i < json_object_array_length(cpuset_obj); i++) { | ||
cpu = json_object_array_get_idx(cpuset_obj, i); | ||
cpu_idx = json_object_get_int(cpu); | ||
if (cpu_idx > max_cpu) { | ||
log_critical(PIN2 "Invalid cpu %u in cpuset %s", cpu_idx, data->cpuset_str); | ||
free(data->cpuset); | ||
CPU_FREE(data->cpuset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have data->cpuset = malloc(data->cpusetsize); few lines above so why replacing free() by CPU_FREE() ?
we should use the same alloc function everywhere: CPU_ALLOC(MAX_CPUS); and CPU_ALLOC_SIZE(MAX_CPUS);
Please use everywhere and squash the first 3 commits in a single one |
cpu_set_t allocated dynamically with CPU_ALLOC need to be manipulated with CPU_*_S() family of macro, otherwise it will be assumed that the size is equal to sizeof(cpu_set_t), leading to undefined behaviours.
Since the use of the dynamique API does not bring a greater range of allowed CPUs in the current state, use the fixed-size API in order to remove reliance on invalid assumptions about the size of the dynamique cpu_set_t value.
Detect up to a configurable number of CPUs, independently from what the libc defaults to.
Free cpuset_str in __shutdown.
73d3eb0
to
23e8ad7
Compare
cpu_set_t allocated dynamically with CPU_ALLOC need to be manipulated
with CPU_*_S() family of macro, otherwise it will be assumed that the
size is equal to sizeof(cpu_set_t), leading to undefined behaviours.
a