On Tue, Jul 04, 2017 at 06:26:22PM +0100, Daniel P. Berrange wrote: > On Tue, Jul 04, 2017 at 05:32:03PM +0100, Daniel P. Berrange wrote: > > On Tue, Jul 04, 2017 at 12:21:21PM +0100, Daniel P. Berrange wrote: > > So I did some debugging and this is wierder than I can imagine possible. > > > > I put a printf statement in virNumaGetMaxNode in qemuxml2argvmock.c > > to print out the return value. > > > > I also put a printf statement in virNumaNodeIsAvailable in virnuma.c > > (in the non-NUMACTL conditional block), that prints out the return > > value received from virNumaGetMaxNode > > > > The first printf displays 7, while the second printf displays -1 > > > > So we're definitely calling our mock override, but the return > > value is getting mangled when seen by the caller, which is a > > giant wtf to me. > > I wrote an isolated test case > > $ cat lib.h > > int get_max(void) __attribute__((noinline)); > > int is_ok(int i); > > > > $ cat lib.c > > #include <stdio.h> > #include "lib.h" > > int get_max(void) > { > fprintf(stderr, "In original max, returning 3\n"); > return 3; > } > > int is_ok(int i) > { > int max = get_max(); > fprintf(stderr, "Received max %d\n", max); > return i > 0 && i <= max; > } > > > > $ cat mock.c > > #include <stdio.h> > #include "lib.h" > > > int get_max(void) > { > fprintf(stderr, "In mock max, returning 7\n"); > return 7; > } > > > > $ cat run.c > > #include <stdio.h> > #include "lib.h" > > int main(int argc, char **argv) > > { > fprintf(stderr, "Is 5 in range ? %d\n", is_ok(5)); > } > > > $ clang -O2 -g -Wall -shared -o libdemo.so -fPIC lib.c > $ clang -O2 -g -Wall -shared -o mock.so -fPIC mock.c > $ clang -O2 -Wall -o run run.c -L. -ldemo > > > $ ./run > In original max, returning 3 > Received max 3 > Is 5 in range ? 0 > $ LD_PRELOAD=mock.so ./run > In mock max, returning 7 > Received max 3 > Is 5 in range ? 0 > > > $ clang -O0 -g -Wall -shared -o libdemo.so -fPIC lib.c > $ LD_PRELOAD=mock.so ./run > In mock max, returning 7 > Received max 7 > Is 5 in range ? 1 > > > So clang is definitely *not* inlining the function, *is* running out mock > function, but none the less getting the return value from the original > function. > > Turning on optimizer debugging i see > > > $ clang -O2 -g -Wall -shared -o libdemo.so -Rpass=.* -fPIC lib.c > lib.c:7:3: remark: marked this call a tail call candidate [-Rpass=tailcallelim] > fprintf(stderr, "In original max, returning 3\n"); > ^ > lib.c:11:15: remark: marked this call a tail call candidate [-Rpass=tailcallelim] > int is_ok(int i) > ^ > lib.c:13:13: remark: marked this call a tail call candidate [-Rpass=tailcallelim] > int max = get_max(); > ^ > lib.c:13:7: remark: marked this call a tail call candidate [-Rpass=tailcallelim] > int max = get_max(); > ^ > lib.c:14:3: remark: marked this call a tail call candidate [-Rpass=tailcallelim] > fprintf(stderr, "Received max %d\n", max); > ^ > > > so, I'm thinking this problem is a result of tail call optimization making > an assumption that is violated when mocking the function. The tail call stuff was a red-herring and not related. After much trial and error I've found that it is possible to make this work by annotating the functions with the attribute "weak". This explicitly tells the compiler that the function is designed to be overridden by an external source, thus preventing any of the call convention optimization clang does. With 'weak' added to virNumaGetMaxNode() the test suite passes on FreeBSD ! Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list