Fast real-process probes for the async index-supervisor contract. They run * only in a child admitted by the exact build-bound worker grammar. */
| 218 | /* Fast real-process probes for the async index-supervisor contract. They run |
| 219 | * only in a child admitted by the exact build-bound worker grammar. */ |
| 220 | static void tf_index_worker_probe(const char *args_json, const char *response_out) { |
| 221 | if (!args_json || !strstr(args_json, "\"__cbm_test_worker\"")) { |
| 222 | return; |
| 223 | } |
| 224 | if (strstr(args_json, "\"clean\"")) { |
| 225 | FILE *response = response_out ? cbm_fopen(response_out, "wb") : NULL; |
| 226 | if (response) { |
| 227 | (void)fputs("{\"probe\":\"clean\"}", response); |
| 228 | (void)fclose(response); |
| 229 | } |
| 230 | (void)fprintf(stderr, "async worker clean probe\n"); |
| 231 | fflush(NULL); |
| 232 | _Exit(response ? 0 : 1); |
| 233 | } |
| 234 | if (strstr(args_json, "\"crash\"")) { |
| 235 | (void)fprintf(stderr, "async worker crash probe\n"); |
| 236 | fflush(NULL); |
| 237 | abort(); |
| 238 | } |
| 239 | if (strstr(args_json, "\"buffered-kill\"")) { |
| 240 | /* The 0-byte-worker-log repro. tf_maybe_run_index_worker has already |
| 241 | * put stderr into the FULL buffering a redirected stderr gets from the |
| 242 | * Windows CRT (see there), so this line only reaches the log if the |
| 243 | * production worker-log entry made the stream crash-durable. |
| 244 | * |
| 245 | * Then die the way the reports die. NOT abort(): Darwin's abort() runs |
| 246 | * the stdio cleanup handler, so it flushes the very buffer this probe |
| 247 | * exists to strand — under abort the reverted build still produced a |
| 248 | * populated log and the repro was silently toothless. SIGKILL cannot be |
| 249 | * caught, blocked or handled, so no cleanup of any kind runs. It is |
| 250 | * also literally #1070's death (`signal=9`) and how #1130's hung worker |
| 251 | * is terminated. */ |
| 252 | cbm_log_info("index.worker.buffered_kill_probe", "phase", "before_kill"); |
| 253 | #ifdef _WIN32 |
| 254 | TerminateProcess(GetCurrentProcess(), 9); |
| 255 | #else |
| 256 | (void)raise(SIGKILL); |
| 257 | #endif |
| 258 | _Exit(2); /* unreachable: neither primitive returns */ |
| 259 | } |
| 260 | if (strstr(args_json, "\"oversize\"")) { |
| 261 | FILE *response = response_out ? cbm_fopen(response_out, "wb") : NULL; |
| 262 | bool written = false; |
| 263 | if (response) { |
| 264 | written = |
| 265 | fseek(response, (long)CBM_DAEMON_RUNTIME_APPLICATION_PAYLOAD_MAX, SEEK_SET) == 0 && |
| 266 | fputc('x', response) != EOF; |
| 267 | written = fclose(response) == 0 && written; |
| 268 | } |
| 269 | (void)fprintf(stderr, "async worker oversized response probe\n"); |
| 270 | fflush(NULL); |
| 271 | _Exit(written ? 0 : 1); |
| 272 | } |
| 273 | if (strstr(args_json, "\"hang-tree\"")) { |
| 274 | (void)signal(SIGTERM, SIG_IGN); |
| 275 | long descendant = 0; |
| 276 | #ifndef _WIN32 |
| 277 | pid_t child = fork(); |
no test coverage detected