Post

Replies

Boosts

Views

Activity

Reply to Initial stack construction
It looks to me like this is the dyld start code https://github.com/apple-opensource/dyld/blob/e3f88907bebb8421f50f0943595f6874de70ebe0/src/dyldInitialization.cpp#L130 As one might expect it just walks over the env pointers plus one NULL to get to the apple pointer.
Dec ’25
Reply to Initial stack construction
I've done a lot more work on this, and I have the impression that this is a bug in macOS, at least on 12 and 13 Intel. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <sys/syslimits.h> // used for debugging apple pointer issues, see // https://bugs.kde.org/show_bug.cgi?id=517304 #define DEBUG_ENV // On Darwin there's this secret fourth argument, 'apple'. // That's kind of like a cut down obfuscated version of auxv. // For the moment we only support the first entry, executable_path= int main(int argc, char *argv[], char *envp[], char *apple[]) { char *pargv = calloc((PATH_MAX+1), sizeof(char)), *pappl = calloc((PATH_MAX+1), sizeof(char)); int i; for (i = 0; envp[i]; i++) { #if defined(DEBUG_ENV) fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i, &envp[i], envp[i]); #endif } #if defined(DEBUG_ENV) fprintf(stderr, "2 slots after envp\n"); fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i, &envp[i], envp[i]); fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i+1, &envp[i+1], envp[i+1]); fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i+2, &envp[i+2], envp[i+2]); fprintf(stderr, "apple %p\n", apple); int j = 0; while (apple[j]) { fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j, &apple[j], apple[j]); ++j; } if (j == 0) { fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j, &apple[j], apple[j]); fprintf(stderr, "apple-main-arg: 1 slot after apple\n"); fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j+1, &apple[j+1], apple[j+1]); } else { fprintf(stderr, "apple-main-arg: 1 slot after apple\n"); fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j, &apple[j], apple[j]); } #endif // envp[i]==NULL; envp[i+1]==apple[0]==executable_path assert(envp[i+1] == apple[0]); // Make sure realpath(argv[0]) == realpath(apple[0]). (realpath resolves // symlinks.) // PJF this changed with macOS 10.14, apple path now has a prefix const char prefix[] = "executable_path="; const size_t prefix_len = strlen(prefix); assert(strncmp(apple[0], prefix, prefix_len) == 0); realpath(apple[0]+prefix_len, pappl); realpath(argv[0], pargv); assert(0 == strcmp(pargv, pappl)); free(pargv); free(pappl); return 0; } If I build and run the above then, on its own it will run OK. If I run it with export DYLD_INSERT_LIBRARIES=/Users/paulf/scratch/valgrind/none/tests/darwin/../../../.in_place/vgpreload_core-amd64-darwin.so then it fails apple-main-arg: i 24 &envp[i] 0x7ff7b1a48af8 envp[i] A__z="*SHLVL 2 slots after envp apple-main-arg: i 25 &envp[i] 0x7ff7b1a48b00 envp[i] (null) apple-main-arg: i 26 &envp[i] 0x7ff7b1a48b08 envp[i] executable_path=./apple-main-arg apple-main-arg: i 27 &envp[i] 0x7ff7b1a48b10 envp[i] (null) apple 0x7ff7b1a48b10 apple-main-arg: j 0 &apple[j] 0x7ff7b1a48b10 apple[j] (null) apple-main-arg: 1 slot after apple apple-main-arg: j 1 &apple[j] 0x7ff7b1a48b18 apple[j] (null) Assertion failed: (envp[i+1] == apple[0]), function main, file apple-main-arg.c, line 51. ./test.ksh: line 7: 3524: Abort Abort
Mar ’26
Reply to Initial stack construction
OK I found the problem and it's on the Valgrind side. A case of the left hand not knowing what the right hand is doing. This is the code that causes the problem static void vg_cleanup_env(void) __attribute__((constructor)); static void vg_cleanup_env(void) { HChar **envp = (HChar**)*_NSGetEnviron(); env_unsetenv(envp, "VALGRIND_LAUNCHER"); env_unsetenv(envp, "DYLD_SHARED_REGION"); // GrP fixme should be more like mash_colon_env() env_unsetenv(envp, "DYLD_INSERT_LIBRARIES"); } 'env_unsetenv' just moves down pointers in the envp table (and the apple param pointers). But it does this after dyld has put the apple pointer into the arguments for main. The fix (from Louis Bruner's port) is to not modify the existing apple pointer table. The first element gets duplicated. So we end up with something like +-----------------+ | | : string table : | | +-----------------+ | NULL | +-----------------+ | executable_path | | executable_path | | executable_path | +-----------------+ | NULL | - - | envp |
Mar ’26
Reply to memchr variant
Missed a zero from the end of the link https://bugs.kde.org/show_bug.cgi?id=437790
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
May ’22
Reply to Getting Valgrind to run on macOS 10.15 Catalina, reboot
I've mostly fixed the issue. It is a problem related to _DATA_CONST. Valgrind needs to be updated so that when the __DATA_CONST load command is handled it shouldn't trigger debuginfo reading. That should happen on the next load command (normally __DATA).
Replies
Boosts
Views
Activity
Dec ’25
Reply to Getting Valgrind to run on macOS 10.15 Catalina, reboot
If all goes well I'll push the code for 10.15 tonight and then move on to macOS 11.
Replies
Boosts
Views
Activity
Dec ’25
Reply to Getting Valgrind to run on macOS 10.15 Catalina, reboot
Code merged, now working on macOS 11. The next "big thing" will be arm64 support.
Replies
Boosts
Views
Activity
Dec ’25
Reply to Initial stack construction
It looks to me like this is the dyld start code https://github.com/apple-opensource/dyld/blob/e3f88907bebb8421f50f0943595f6874de70ebe0/src/dyldInitialization.cpp#L130 As one might expect it just walks over the env pointers plus one NULL to get to the apple pointer.
Replies
Boosts
Views
Activity
Dec ’25
Reply to Initial stack construction
I've done a lot more work on this, and I have the impression that this is a bug in macOS, at least on 12 and 13 Intel. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <sys/syslimits.h> // used for debugging apple pointer issues, see // https://bugs.kde.org/show_bug.cgi?id=517304 #define DEBUG_ENV // On Darwin there's this secret fourth argument, 'apple'. // That's kind of like a cut down obfuscated version of auxv. // For the moment we only support the first entry, executable_path= int main(int argc, char *argv[], char *envp[], char *apple[]) { char *pargv = calloc((PATH_MAX+1), sizeof(char)), *pappl = calloc((PATH_MAX+1), sizeof(char)); int i; for (i = 0; envp[i]; i++) { #if defined(DEBUG_ENV) fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i, &envp[i], envp[i]); #endif } #if defined(DEBUG_ENV) fprintf(stderr, "2 slots after envp\n"); fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i, &envp[i], envp[i]); fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i+1, &envp[i+1], envp[i+1]); fprintf(stderr, "apple-main-arg: i %d &envp[i] %p envp[i] %s\n", i+2, &envp[i+2], envp[i+2]); fprintf(stderr, "apple %p\n", apple); int j = 0; while (apple[j]) { fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j, &apple[j], apple[j]); ++j; } if (j == 0) { fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j, &apple[j], apple[j]); fprintf(stderr, "apple-main-arg: 1 slot after apple\n"); fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j+1, &apple[j+1], apple[j+1]); } else { fprintf(stderr, "apple-main-arg: 1 slot after apple\n"); fprintf(stderr, "apple-main-arg: j %d &apple[j] %p apple[j] %s\n", j, &apple[j], apple[j]); } #endif // envp[i]==NULL; envp[i+1]==apple[0]==executable_path assert(envp[i+1] == apple[0]); // Make sure realpath(argv[0]) == realpath(apple[0]). (realpath resolves // symlinks.) // PJF this changed with macOS 10.14, apple path now has a prefix const char prefix[] = "executable_path="; const size_t prefix_len = strlen(prefix); assert(strncmp(apple[0], prefix, prefix_len) == 0); realpath(apple[0]+prefix_len, pappl); realpath(argv[0], pargv); assert(0 == strcmp(pargv, pappl)); free(pargv); free(pappl); return 0; } If I build and run the above then, on its own it will run OK. If I run it with export DYLD_INSERT_LIBRARIES=/Users/paulf/scratch/valgrind/none/tests/darwin/../../../.in_place/vgpreload_core-amd64-darwin.so then it fails apple-main-arg: i 24 &envp[i] 0x7ff7b1a48af8 envp[i] A__z="*SHLVL 2 slots after envp apple-main-arg: i 25 &envp[i] 0x7ff7b1a48b00 envp[i] (null) apple-main-arg: i 26 &envp[i] 0x7ff7b1a48b08 envp[i] executable_path=./apple-main-arg apple-main-arg: i 27 &envp[i] 0x7ff7b1a48b10 envp[i] (null) apple 0x7ff7b1a48b10 apple-main-arg: j 0 &apple[j] 0x7ff7b1a48b10 apple[j] (null) apple-main-arg: 1 slot after apple apple-main-arg: j 1 &apple[j] 0x7ff7b1a48b18 apple[j] (null) Assertion failed: (envp[i+1] == apple[0]), function main, file apple-main-arg.c, line 51. ./test.ksh: line 7: 3524: Abort Abort
Replies
Boosts
Views
Activity
Mar ’26
Reply to Initial stack construction
OK I found the problem and it's on the Valgrind side. A case of the left hand not knowing what the right hand is doing. This is the code that causes the problem static void vg_cleanup_env(void) __attribute__((constructor)); static void vg_cleanup_env(void) { HChar **envp = (HChar**)*_NSGetEnviron(); env_unsetenv(envp, "VALGRIND_LAUNCHER"); env_unsetenv(envp, "DYLD_SHARED_REGION"); // GrP fixme should be more like mash_colon_env() env_unsetenv(envp, "DYLD_INSERT_LIBRARIES"); } 'env_unsetenv' just moves down pointers in the envp table (and the apple param pointers). But it does this after dyld has put the apple pointer into the arguments for main. The fix (from Louis Bruner's port) is to not modify the existing apple pointer table. The first element gets duplicated. So we end up with something like +-----------------+ | | : string table : | | +-----------------+ | NULL | +-----------------+ | executable_path | | executable_path | | executable_path | +-----------------+ | NULL | - - | envp |
Replies
Boosts
Views
Activity
Mar ’26