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
Bring merge sort and insertion sort cmp function semantics together #17473
Conversation
I rebased on master and removed sdb modifications after sending radareorg/sdb#212 |
Please rebase on top of the master and sync SDB here since that PR was merged. |
Seems it has broken the reverse debugger:
|
Yes, I didn't notice it at first because the test is also failing on my machine (Fedora 32), but differently. I saw the same result before and after the PR. I'll install Ubuntu to try to reproduce it. |
I installed Ubuntu bionic in chroot, and the test passes on this branch, I'll try something else. |
I think it may be because I don't have AVX extensions on my (old) CPU, see logs of a github action on my account, with additional debug info:
https://github.com/anisse/radare2/pull/3/checks?check_run_id=1005021519 Now I need to find a machine with those or debug through github actions :-/ |
Apparently glibc has a function to do a faster memset using avx512: vzeroupper. That's what the trace debugger is hitting, trying to get the value of the ymm0-15 registers, and failing because this isn't implemented. I'm pretty sure this PR accidentally fixed something (I don't know what) which is now making this trace debugger test fail. I wouldn't mind a second pair of eyes for this. I could add a fake case for getting the value of a 256bits register, just like 128bits (which isn't really implemented). What do you think ? |
I'm not sure about this. By definition in r_list.h, RListComparator should return -1, 0, 1, so I think it is just wrong to pass a RListComparator that returns a bool. IMHO it is wrong to use |
I've thought about this as well, but decided against this, for the following reasons:
I could provide a different PR that changes the comparators, but IMHO it would require changing the insertion sort as well, to stop working as it always did, since the "code is the API", and the behaviour should be the same for both functions to avoid any surprise once the list size changes; ideally this should be propagated in sdb as well, that already took this fix. What do you think ? Right now there are lists in the code that aren't properly sorted: I've found the register lists for x86, aarch64, and the new one for arm32 in PR #17462 . |
I think they are not properly sorted because of this bool/int mess. If you convert the comparator functions to use -1/0/1, they should work.
The fact that it works is just a side effect, IMO. However, in general in C comparator functions like
I agree, and I think they do, if the right comparator function (that is one that returns -1/0/1) is used in both cases. If merge or insertion sort don't work properly, provided with a -1/0/1 comparator function, than that is definitely a bug.
I didn't dig into the history, but the different semantic at the 0 boundary is probably only a "small issue" and probably should affect only the relative sorting of two elements with the same value according to All this to say that if there are problems when moving from insertion to merge sort, it is probably just because the comparator function passed to insertion_sort abused the way the sorting is implemented, but those are actually wrong. We should change those comparator functions. You can also see that you are actually casting a boolean ( |
It's not a small issue, once merge sort is used, lists aren't sorted at all. You can look at the test fixes to see how the order changes.
I agree it's a comparator bug, but this PR has the advantage of entirely fixing this bug class. It will reappear again, because casting the function once to (RListComparator) is slightly easier than casting both const void*. Here is my proposal:
|
I've updated the PR with my proposal and changed the main description. |
Thanks! Much better now ;) Let's wait for CI. Please just fix that small comment (unless there is a reason to keep it like that), then it's ok for me. |
This fixes the trace debugger test by removing the content of rdx, which changes on Fedora glibc, or recent Ubuntu with glibc AVX2 support. Ideally this test should be modified to depend less on the system libc.
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.
Change the commit title and add ##anal i think this is an important change and it shuold be in the changelog, the message should make clear the function variable and reflines order is what is mainly affected. Do you have a screenshot of the change in reflines after this change? is the change in sdb correct or should be changed again because of the cmp <=
@@ -1334,9 +1334,9 @@ var char ** var_20h @ rbp-0x20 | |||
var int64_t var_14h @ rbp-0x14 | |||
var void * var_10h @ rbp-0x10 | |||
var int64_t var_4h @ rbp-0x4 | |||
arg int argc @ rdi |
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.
I still think there is something wrong here. I would expect variables and arguments to be shown in the "right order", not just sorted by register names. I know this depends on aBI, etc. but it kinda made sense to have rdi
, rsi
, rdx
, while I find this new sorting inappropriate in this particular context. @XVilka @thestr4ng3r @kazarmy WDYT?
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.
I agree, the argument order feels reversed. I'm not sure how to address that here though.
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.
this needs a little bit more investigation. Maybe it's just the way it is, but maybe we are missing something.
Should it be for all commits ?
I'm not sure how to test, but here is a small example; before:
after:
(no change)
Yes, I've made sure we keep the same behaviour with sdb. |
…#anal Merge sort uses cmp (a, b) < 0 for its first test branch, and insertion sort cmp (a, b) > 0 ; which means the 0 boundary goes in one case in one branch, and in the other sort function in the other branch. It makes it possible to support compare function that return true/false instead of -1/0/1; although this isn't an acceptable use of RListComparator, this prevents future bugs from appearing, because this works with insertion sort, but not merge sort. The main advantage of this patch is that both sort functions should sort equal elements the same way. This stability is important for zignatures for example.
I did it for commits that impact sort order and test fixes. |
@XVilka @thestr4ng3r @trufae someone please have another look at this and merge if you think it's ok! |
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.
The comparison change looks good to merge. What looks wrong is the reversed order of the arguments/etc like @ret2libc pointed out.
xmm1h | ||
xmm1 | ||
ds | ||
xmm1l |
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.
i think this order is messed up
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.
It is, but that's because the register offsets are the same for xmm1l and ds : 184
radare2/libr/debug/p/native/linux/reg/linux-x64.h
Lines 159 to 161 in 2dfa75c
"xmm@fpu xmm1 .128 176 16\n" | |
"fpu xmm1h .64 176 8\n" | |
"fpu xmm1l .64 184 8\n" |
"seg@gpr ds .64 184 0\n" |
ymm14 | ||
ymm13 | ||
ymm12 | ||
ymm11 |
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.
its properly (reversed) sorted
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.
Considering the original functions wants to sort in order, this is the issue this PR fixes:
https://github.com/radareorg/radare2/blob/master/libr/reg/reg.c#L200-L203
You can verify this by always using insertion sort instead here:
https://github.com/radareorg/radare2/blob/master/libr/util/list.c#L573-L577
r12 | ||
dr3 | ||
mxcr_mask |
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.
random order :?
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.
This corresponds to the offset of the register: dr3 is at 24 and mxcr_mask at 28:
dr3: https://github.com/radareorg/radare2/blob/master/libr/anal/p/anal_x86_cs.c#L3576
mxcr_mask: https://github.com/radareorg/radare2/blob/master/libr/anal/p/anal_x86_cs.c#L3604
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.
Sorry, wrong links, this is the file:
"drx dr3 .64 24 0\n" |
"fpu mxcr_mask .32 28 0\n" |
@XVilka @trufae as said in previous comments, we think those "random" orders are just because they were never really sorted in the first place. If you look at those tests, the original order was not really better than the new one. It seems like somehow they seemed sorted, but there is no real sorting underneath. Probably those commands should sort the things before printing them themselves. |
lgtm |
@anisse can you make the PR ready if it's ok to merge? Just to be sure you don't intend to add anything to this. Thanks again for this! |
dismissing because trufae has accepted the changes.
Merge sort uses cmp (a, b) < 0 for its first test branch, and insertion
sort cmp (a, b) > 0 ; which means the 0 boundary goes in one case in one
branch, and in the other sort function in the other branch.
We keep the semantics of the insertion sort, because it allows stability between
the two sort functions for equal elements.
Update tests that were broken because of wrong register ordering.
Your checklist for this pull request
Detailed description
Register order changed on arm32 after adding more register at the end: everything was seemingly in a random order. It's because the list went over 43 elements, and started using merge sort instead of insertion sort. This PR make merge sort behave properly with compare functions that return a bool.
Test plan
...
Closing issues
This should unblock test regression from PR #17462