NOTE: Please keep this function in sync with its copy at: * dmtcp_nocheckpoint.cpp:restoreUserLDPRELOAD() */
| 58 | * dmtcp_nocheckpoint.cpp:restoreUserLDPRELOAD() |
| 59 | */ |
| 60 | void |
| 61 | restoreUserLDPRELOAD() |
| 62 | { |
| 63 | /* A call to setenv() can result in a call to malloc(). The setenv() call may |
| 64 | * also grab a low-level libc lock before calling malloc. The malloc() |
| 65 | * wrapper, if present, will try to acquire the wrapper lock. This can lead |
| 66 | * to a deadlock in the following scenario: |
| 67 | * |
| 68 | * T1 (main thread): fork() -> acquire exclusive lock |
| 69 | * T2 (ckpt thread): setenv() -> acquire low-level libc lock -> |
| 70 | * malloc -> wait for wrapper-exec lock. |
| 71 | * T1: setenv() -> block on low-level libc lock (held by T2). |
| 72 | * |
| 73 | * The simpler solution would have been to not call setenv from DMTCP, and |
| 74 | * use putenv instead. This would require larger change. |
| 75 | * |
| 76 | * The solution used here is to set LD_PRELOAD to "" before * user main(). |
| 77 | * This is as good as unsetting it. Later, the ckpt-thread * can unset it |
| 78 | * if it is still NULL, but then there is a possibility of a race between |
| 79 | * user code and ckpt-thread. |
| 80 | */ |
| 81 | |
| 82 | // We have now successfully used LD_PRELOAD to execute prior to main() |
| 83 | // Next, hide our value of LD_PRELOAD, in a global variable. |
| 84 | // At checkpoint and restart time, we will no longer need our LD_PRELOAD. |
| 85 | // We will need it in only one place: |
| 86 | // when the user application makes an exec call: |
| 87 | // If anybody calls our execwrapper, we will reset LD_PRELOAD then. |
| 88 | // EXCEPTION: If anybody directly calls _real_execve with env arg of NULL, |
| 89 | // they will not be part of DMTCP computation. |
| 90 | // This has the advantage that our value of LD_PRELOAD will always come |
| 91 | // before any paths set by user application. |
| 92 | // Also, bash likes to keep its own envp, but we will interact with bash only |
| 93 | // within the exec wrapper. |
| 94 | // NOTE: If the user called exec("ssh ..."), we currently catch this in |
| 95 | // src/pugin/dmtcp_ssh.cp:main(), and edit this into |
| 96 | // exec("dmtcp_launch ... dmtcp_ssh ..."), and re-execute. |
| 97 | // NOTE: If the user called exec("dmtcp_nocheckpoint ..."), we will |
| 98 | // reset LD_PRELOAD back to ENV_VAR_ORIG_LD_PRELOAD in dmtcp_nocheckpoint |
| 99 | char *preload = getenv("LD_PRELOAD"); |
| 100 | char *userPreload = getenv(ENV_VAR_ORIG_LD_PRELOAD); |
| 101 | |
| 102 | JASSERT(userPreload == NULL || strlen(userPreload) <= strlen(preload)) |
| 103 | (preload)(userPreload); |
| 104 | |
| 105 | // Destructively modify environment variable "LD_PRELOAD" in place: |
| 106 | preload[0] = '\0'; |
| 107 | if (userPreload == NULL) { |
| 108 | // _dmtcp_unsetenv("LD_PRELOAD"); |
| 109 | } else { |
| 110 | strcat(preload, userPreload); |
| 111 | |
| 112 | // setenv("LD_PRELOAD", userPreload, 1); |
| 113 | } |
| 114 | JTRACE("LD_PRELOAD") (preload) (userPreload) (getenv(ENV_VAR_HIJACK_LIBS)) |
| 115 | (getenv(ENV_VAR_HIJACK_LIBS_M32)) (getenv("LD_PRELOAD")); |
| 116 | } |
| 117 |
no outgoing calls
no test coverage detected