From: Nicholas Nethercote Date: Sun, 16 Aug 2009 00:00:17 +0000 (+0000) Subject: Fix the access_extended wrapper, which was rather broken. That's what I get X-Git-Tag: svn/VALGRIND_3_5_0~24 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9acc4cc4d8d6fb4b21af9ed409b86d9963c6ad2b;p=thirdparty%2Fvalgrind.git Fix the access_extended wrapper, which was rather broken. That's what I get for not testing properly. Added a regtest for it too. Fixes bug 200760 (again, properly this time). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10826 --- diff --git a/coregrind/m_syswrap/syswrap-darwin.c b/coregrind/m_syswrap/syswrap-darwin.c index 23dacb892d..86c974f9ae 100644 --- a/coregrind/m_syswrap/syswrap-darwin.c +++ b/coregrind/m_syswrap/syswrap-darwin.c @@ -2069,6 +2069,9 @@ PRE(access_extended) { PRINT("access_extended( %#lx(%s), %lu, %#lx, %lu )", ARG1, (char *)ARG1, ARG2, ARG3, ARG4); + // XXX: the accessx_descriptor struct contains padding, so this can cause + // unnecessary undefined value errors. But you arguably shouldn't be + // passing undefined values to the kernel anyway... PRE_REG_READ4(int, "access_extended", void *, entries, vki_size_t, size, vki_errno_t *, results, vki_uid_t *, uid); PRE_MEM_READ("access_extended(entries)", ARG1, ARG2 ); @@ -2084,18 +2087,17 @@ POST(access_extended) // shortest possible string section. The shortest string section allowed // consists of a single one-char string (plus the NUL char). Hence the // '2'. - struct vki_accessx_descriptor* entries = (struct vki_accessx_descriptor*)ARG2; + struct vki_accessx_descriptor* entries = (struct vki_accessx_descriptor*)ARG1; SizeT size = ARG2; Int n_descs = (size - 2) / sizeof(struct accessx_descriptor); - Int i = 0; // Current position in the descriptors section array. + Int i; // Current position in the descriptors section array. Int u; // Upper bound on the length of the descriptors array - // (recomputed each time around the loop) + // (recomputed each time around the loop) vg_assert(n_descs > 0); // Step through the descriptors, lowering 'n_descs' until we know we've // reached the string section. - while (True) - { + for (i = 0; True; i++) { // If we're past our estimate, we must be one past the end of the // descriptors section (ie. at the start of the string section). Stop. if (i >= n_descs) diff --git a/none/tests/darwin/Makefile.am b/none/tests/darwin/Makefile.am index 3d06695ce0..391fb59996 100644 --- a/none/tests/darwin/Makefile.am +++ b/none/tests/darwin/Makefile.am @@ -4,10 +4,12 @@ include $(top_srcdir)/Makefile.tool-tests.am dist_noinst_SCRIPTS = filter_stderr EXTRA_DIST = \ + access_extended.stderr.exp access_extended.vgtest \ apple-main-arg.stderr.exp apple-main-arg.vgtest \ rlimit.stderr.exp rlimit.vgtest check_PROGRAMS = \ + access_extended \ apple-main-arg \ rlimit diff --git a/none/tests/darwin/access_extended.c b/none/tests/darwin/access_extended.c new file mode 100644 index 0000000000..bf56154cac --- /dev/null +++ b/none/tests/darwin/access_extended.c @@ -0,0 +1,48 @@ +// This is a test for access_extended(), one of the more ridiculous syscalls +// ever devised. For bug 200760. See the comments on the wrapper in +// syswrap-darwin.c to understand what is going on here. + +#include +#include +#include +#include +#include + +int main(void) +{ + char* name1 = "access_extended.c"; + char* name2 = "no_such_file"; + // Space for three descriptors and the two strings (and NUL chars for them). + size_t entries_szB = + sizeof(struct accessx_descriptor) * 3 + + strlen(name1) + 1 + + strlen(name2) + 1; + struct accessx_descriptor* entries = malloc(entries_szB); + char* string1 = (char*)&entries[3]; + char* string2 = string1 + strlen(name1) + 1; + int results[3]; + int retval; + + entries[0].ad_name_offset = string1 - (char*)entries; + entries[1].ad_name_offset = 0; // reuse the previous entry's string + entries[2].ad_name_offset = string2 - (char*)entries; + entries[0].ad_flags = F_OK; // succeeds + entries[1].ad_flags = X_OK; // fails + entries[2].ad_flags = F_OK; // fails + strcpy(string1, name1); + strcpy(string2, name2); + + retval = syscall(SYS_access_extended, entries, entries_szB, results, + /*uid--unused?*/0); + + fprintf(stderr, "retval = %d\n", retval); + fprintf(stderr, "%s(F_OK) = %d (%s)\n", + name1, results[0], strerror(results[0])); + fprintf(stderr, "%s(X_OK) = %d (%s)\n", + name1, results[1], strerror(results[1])); + fprintf(stderr, "%s(F_OK) = %d (%s)\n", + name2, results[2], strerror(results[2])); + + return 0; +} + diff --git a/none/tests/darwin/access_extended.stderr.exp b/none/tests/darwin/access_extended.stderr.exp new file mode 100644 index 0000000000..65438c5b34 --- /dev/null +++ b/none/tests/darwin/access_extended.stderr.exp @@ -0,0 +1,4 @@ +retval = 0 +access_extended.c(F_OK) = 0 (Unknown error: 0) +access_extended.c(X_OK) = 13 (Permission denied) +no_such_file(F_OK) = 2 (No such file or directory) diff --git a/none/tests/darwin/access_extended.vgtest b/none/tests/darwin/access_extended.vgtest new file mode 100644 index 0000000000..29257b1c64 --- /dev/null +++ b/none/tests/darwin/access_extended.vgtest @@ -0,0 +1,2 @@ +prog: access_extended +vgopts: -q