<div dir="ltr"><div>Some questions and comments on the memcmp() issue from the 2022-12-23 notes.html entry.</div><div><br></div><div>I suspect that memcmp("a", "abc", 4); is a simplified version of the actual case that caused an issue with ASAN. What was the actual case like? Was part of either buffer in unallocated memory? If so, could that memory be accessed in some other scenario?</div><div><br></div><div>xmemcmp() doesn't do the same thing as memcmp(). memcmp() compares char as unsigned, and xmemcmp uses plain char *, so if plain char is signed by default, xmemcmp will return the opposite "sense" from memcmp for e.g. xmemcmp("0xF0", "a", 2). Easy fix is to use</div><div><br></div><div>  while (len--) if ((ii = *(unsigned char *)one++ - *(unsigned char *)two++)) break;</div><div><br></div><div>It appears memcmp() is only used for equality testing now, but if you leave xmemcmp() unchanged it could cause trouble later if it's used for less/equal/greater comparison.</div><div><br></div><div>As for ASAN, you can disable the catching of memcmp. I know nothing of toybox or linux or ASAN, so I may be off base here, but here's my testing:</div><div><br></div><div>// xwraptest.c</div>#include <stdio.h><br>#include <stdlib.h><br>#include <string.h><br><br>// ASAN flips out about memcmp("a", "abc", 4) but the result is well-defined.<br>// This one's guaranteed to stop at len _or_ the first difference.<br>int xmemcmp(char *one, char *two, unsigned long len)<br>{<br>  int ii = 0;<br><br>  while (len--) if ((ii = *(unsigned char*)one++ - *(unsigned char*)two++)) break;<br><br>  return ii;<br>}<br><br>int main()<br>{<br>    char *a = strdup("a");<br>    char *b = strdup("abc");<br>    printf("memcmp(a, b, 4):  %d\n", memcmp(a, b, 4));<br>    printf("xmemcmp(a, b, 4): %d\n", xmemcmp(a, b, 4));<br>    free(a);<br>    free(b);<br>    return 0;<br>}<br><div><br></div><div>Then, in WSL Ubuntu:</div><div>ray@radon:/mnt/e/r/toybox/z$ gcc xwraptest.c -Wall -Wextra -o foo -fsanitize=address -g<br>ray@radon:/mnt/e/r/toybox/z$ ASAN_OPTIONS=intercept_memcmp=0:strict_memcmp=0 ./foo<br>memcmp(a, b, 4):  -1<br>xmemcmp(a, b, 4): -98<br>ray@radon:/mnt/e/r/toybox/z$ ASAN_OPTIONS=intercept_memcmp=1:strict_memcmp=0 ./foo<br>memcmp(a, b, 4):  -1<br>xmemcmp(a, b, 4): -98<br>ray@radon:/mnt/e/r/toybox/z$ ASAN_OPTIONS=intercept_memcmp=1:strict_memcmp=1 ./foo<br>=================================================================<br>==583==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000012 at pc 0x7fd32d66cd00 bp 0x7ffc7af61e80 sp 0x7ffc7af61628<br></div><div>[... more error info ...]</div><div><br></div><div>No ASAN memcmp testing is done if intercept_memcmp is 0. Not sure if turning off strict_memcmp will shut up the error you encountered, but it does for the case above. You can also compile the options into the source (see <a href="https://github.com/google/sanitizers/wiki/AddressSanitizerFlags" target="_blank">https://github.com/google/sanitizers/wiki/AddressSanitizerFlags</a>), e.g.:</div><div><br></div><div>const char *__asan_default_options() {<br>  return "intercept_memcmp=1:strict_memcmp=0";<br>}<br></div><div><br></div><div>ASAN may be overly paranoid with strict_memcmp, but I think it's looking (with strict) to see if any of the two buffers fall in unallocated (or even just uninitialized? how would it know?) memory.</div><div><br></div><div>Here's an interesting anecdote about accessing allocated but uninitialized memory: <a href="https://youtu.be/kPR8h4-qZdk?t=1144" target="_blank">https://youtu.be/kPR8h4-qZdk?t=1144</a> (The whole talk is interesting even if you don't do C++.) (I don't either.)<br></div><div><br></div></div>