test_util_slow.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /* Copyright (c) 2001-2004, Roger Dingledine.
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "orconfig.h"
  6. #define UTIL_PRIVATE
  7. #define SUBPROCESS_PRIVATE
  8. #include "lib/crypt_ops/crypto_cipher.h"
  9. #include "lib/log/log.h"
  10. #include "lib/process/subprocess.h"
  11. #include "lib/process/waitpid.h"
  12. #include "lib/string/printf.h"
  13. #include "lib/time/compat_time.h"
  14. #include "test/test.h"
  15. #include <errno.h>
  16. #include <string.h>
  17. #ifndef BUILDDIR
  18. #define BUILDDIR "."
  19. #endif
  20. #ifdef _WIN32
  21. #define notify_pending_waitpid_callbacks() STMT_NIL
  22. #define TEST_CHILD "test-child.exe"
  23. #define EOL "\r\n"
  24. #else
  25. #define TEST_CHILD (BUILDDIR "/src/test/test-child")
  26. #define EOL "\n"
  27. #endif /* defined(_WIN32) */
  28. #ifdef _WIN32
  29. /* I've assumed Windows doesn't have the gap between fork and exec
  30. * that causes the race condition on unix-like platforms */
  31. #define MATCH_PROCESS_STATUS(s1,s2) ((s1) == (s2))
  32. #else /* !(defined(_WIN32)) */
  33. /* work around a race condition of the timing of SIGCHLD handler updates
  34. * to the process_handle's fields, and checks of those fields
  35. *
  36. * TODO: Once we can signal failure to exec, change PROCESS_STATUS_RUNNING to
  37. * PROCESS_STATUS_ERROR (and similarly with *_OR_NOTRUNNING) */
  38. #define PROCESS_STATUS_RUNNING_OR_NOTRUNNING (PROCESS_STATUS_RUNNING+1)
  39. #define IS_RUNNING_OR_NOTRUNNING(s) \
  40. ((s) == PROCESS_STATUS_RUNNING || (s) == PROCESS_STATUS_NOTRUNNING)
  41. /* well, this is ugly */
  42. #define MATCH_PROCESS_STATUS(s1,s2) \
  43. ( (s1) == (s2) \
  44. ||((s1) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
  45. && IS_RUNNING_OR_NOTRUNNING(s2)) \
  46. ||((s2) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
  47. && IS_RUNNING_OR_NOTRUNNING(s1)))
  48. #endif /* defined(_WIN32) */
  49. /** Helper function for testing tor_spawn_background */
  50. static void
  51. run_util_spawn_background(const char *argv[], const char *expected_out,
  52. const char *expected_err, int expected_exit,
  53. int expected_status)
  54. {
  55. int retval, exit_code;
  56. ssize_t pos;
  57. process_handle_t *process_handle=NULL;
  58. char stdout_buf[100], stderr_buf[100];
  59. int status;
  60. /* Start the program */
  61. #ifdef _WIN32
  62. status = tor_spawn_background(NULL, argv, NULL, &process_handle);
  63. #else
  64. status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
  65. #endif
  66. notify_pending_waitpid_callbacks();
  67. /* the race condition doesn't affect status,
  68. * because status isn't updated by the SIGCHLD handler,
  69. * but we still need to handle PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
  70. tt_assert(MATCH_PROCESS_STATUS(expected_status, status));
  71. if (status == PROCESS_STATUS_ERROR) {
  72. tt_ptr_op(process_handle, OP_EQ, NULL);
  73. return;
  74. }
  75. tt_ptr_op(process_handle, OP_NE, NULL);
  76. /* When a spawned process forks, fails, then exits very quickly,
  77. * (this typically occurs when exec fails)
  78. * there is a race condition between the SIGCHLD handler
  79. * updating the process_handle's fields, and this test
  80. * checking the process status in those fields.
  81. * The SIGCHLD update can occur before or after the code below executes.
  82. * This causes intermittent failures in spawn_background_fail(),
  83. * typically when the machine is under load.
  84. * We use PROCESS_STATUS_RUNNING_OR_NOTRUNNING to avoid this issue. */
  85. /* the race condition affects the change in
  86. * process_handle->status from RUNNING to NOTRUNNING */
  87. tt_assert(MATCH_PROCESS_STATUS(expected_status, process_handle->status));
  88. #ifndef _WIN32
  89. notify_pending_waitpid_callbacks();
  90. /* the race condition affects the change in
  91. * process_handle->waitpid_cb to NULL,
  92. * so we skip the check if expected_status is ambiguous,
  93. * that is, PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
  94. tt_assert(process_handle->waitpid_cb != NULL
  95. || expected_status == PROCESS_STATUS_RUNNING_OR_NOTRUNNING);
  96. #endif /* !defined(_WIN32) */
  97. #ifdef _WIN32
  98. tt_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
  99. tt_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
  100. tt_assert(process_handle->stdin_pipe != INVALID_HANDLE_VALUE);
  101. #else
  102. tt_assert(process_handle->stdout_pipe >= 0);
  103. tt_assert(process_handle->stderr_pipe >= 0);
  104. tt_assert(process_handle->stdin_pipe >= 0);
  105. #endif /* defined(_WIN32) */
  106. /* Check stdout */
  107. pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
  108. sizeof(stdout_buf) - 1);
  109. tt_assert(pos >= 0);
  110. stdout_buf[pos] = '\0';
  111. tt_int_op(strlen(expected_out),OP_EQ, pos);
  112. tt_str_op(expected_out,OP_EQ, stdout_buf);
  113. notify_pending_waitpid_callbacks();
  114. /* Check it terminated correctly */
  115. retval = tor_get_exit_code(process_handle, 1, &exit_code);
  116. tt_int_op(PROCESS_EXIT_EXITED,OP_EQ, retval);
  117. tt_int_op(expected_exit,OP_EQ, exit_code);
  118. // TODO: Make test-child exit with something other than 0
  119. #ifndef _WIN32
  120. notify_pending_waitpid_callbacks();
  121. tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
  122. #endif
  123. /* Check stderr */
  124. pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
  125. sizeof(stderr_buf) - 1);
  126. tt_assert(pos >= 0);
  127. stderr_buf[pos] = '\0';
  128. tt_str_op(expected_err,OP_EQ, stderr_buf);
  129. tt_int_op(strlen(expected_err),OP_EQ, pos);
  130. notify_pending_waitpid_callbacks();
  131. done:
  132. if (process_handle)
  133. tor_process_handle_destroy(process_handle, 1);
  134. }
  135. /** Check that we can launch a process and read the output */
  136. static void
  137. test_util_spawn_background_ok(void *ptr)
  138. {
  139. const char *argv[] = {TEST_CHILD, "--test", NULL};
  140. const char *expected_out = "OUT"EOL "--test"EOL "SLEEPING"EOL "DONE" EOL;
  141. const char *expected_err = "ERR"EOL;
  142. (void)ptr;
  143. run_util_spawn_background(argv, expected_out, expected_err, 0,
  144. PROCESS_STATUS_RUNNING);
  145. }
  146. /** Check that failing to find the executable works as expected */
  147. static void
  148. test_util_spawn_background_fail(void *ptr)
  149. {
  150. const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL};
  151. const char *expected_err = "";
  152. char expected_out[1024];
  153. char code[32];
  154. #ifdef _WIN32
  155. const int expected_status = PROCESS_STATUS_ERROR;
  156. #else
  157. /* TODO: Once we can signal failure to exec, set this to be
  158. * PROCESS_STATUS_RUNNING_OR_ERROR */
  159. const int expected_status = PROCESS_STATUS_RUNNING_OR_NOTRUNNING;
  160. #endif /* defined(_WIN32) */
  161. memset(expected_out, 0xf0, sizeof(expected_out));
  162. memset(code, 0xf0, sizeof(code));
  163. (void)ptr;
  164. tor_snprintf(code, sizeof(code), "%x/%x",
  165. 9 /* CHILD_STATE_FAILEXEC */ , ENOENT);
  166. tor_snprintf(expected_out, sizeof(expected_out),
  167. "ERR: Failed to spawn background process - code %s\n", code);
  168. run_util_spawn_background(argv, expected_out, expected_err, 255,
  169. expected_status);
  170. }
  171. /** Test that reading from a handle returns a partial read rather than
  172. * blocking */
  173. static void
  174. test_util_spawn_background_partial_read_impl(int exit_early)
  175. {
  176. const int expected_exit = 0;
  177. const int expected_status = PROCESS_STATUS_RUNNING;
  178. int retval, exit_code;
  179. ssize_t pos = -1;
  180. process_handle_t *process_handle=NULL;
  181. int status;
  182. char stdout_buf[100], stderr_buf[100];
  183. const char *argv[] = {TEST_CHILD, "--test", NULL};
  184. const char *expected_out[] = { "OUT" EOL "--test" EOL "SLEEPING" EOL,
  185. "DONE" EOL,
  186. NULL };
  187. const char *expected_err = "ERR" EOL;
  188. #ifndef _WIN32
  189. int eof = 0;
  190. #endif
  191. int expected_out_ctr;
  192. if (exit_early) {
  193. argv[1] = "--hang";
  194. expected_out[0] = "OUT"EOL "--hang"EOL "SLEEPING" EOL;
  195. }
  196. /* Start the program */
  197. #ifdef _WIN32
  198. status = tor_spawn_background(NULL, argv, NULL, &process_handle);
  199. #else
  200. status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
  201. #endif
  202. tt_int_op(expected_status,OP_EQ, status);
  203. tt_assert(process_handle);
  204. tt_int_op(expected_status,OP_EQ, process_handle->status);
  205. /* Check stdout */
  206. for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) {
  207. #ifdef _WIN32
  208. pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
  209. sizeof(stdout_buf) - 1, NULL);
  210. #else
  211. /* Check that we didn't read the end of file last time */
  212. tt_assert(!eof);
  213. pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
  214. sizeof(stdout_buf) - 1, NULL, &eof);
  215. #endif /* defined(_WIN32) */
  216. log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
  217. /* We would have blocked, keep on trying */
  218. if (0 == pos)
  219. continue;
  220. tt_assert(pos > 0);
  221. stdout_buf[pos] = '\0';
  222. tt_str_op(expected_out[expected_out_ctr],OP_EQ, stdout_buf);
  223. tt_int_op(strlen(expected_out[expected_out_ctr]),OP_EQ, pos);
  224. expected_out_ctr++;
  225. }
  226. if (exit_early) {
  227. tor_process_handle_destroy(process_handle, 1);
  228. process_handle = NULL;
  229. goto done;
  230. }
  231. /* The process should have exited without writing more */
  232. #ifdef _WIN32
  233. pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
  234. sizeof(stdout_buf) - 1,
  235. process_handle);
  236. tt_int_op(0,OP_EQ, pos);
  237. #else /* !(defined(_WIN32)) */
  238. if (!eof) {
  239. /* We should have got all the data, but maybe not the EOF flag */
  240. pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
  241. sizeof(stdout_buf) - 1,
  242. process_handle, &eof);
  243. tt_int_op(0,OP_EQ, pos);
  244. tt_assert(eof);
  245. }
  246. /* Otherwise, we got the EOF on the last read */
  247. #endif /* defined(_WIN32) */
  248. /* Check it terminated correctly */
  249. retval = tor_get_exit_code(process_handle, 1, &exit_code);
  250. tt_int_op(PROCESS_EXIT_EXITED,OP_EQ, retval);
  251. tt_int_op(expected_exit,OP_EQ, exit_code);
  252. // TODO: Make test-child exit with something other than 0
  253. /* Check stderr */
  254. pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
  255. sizeof(stderr_buf) - 1);
  256. tt_assert(pos >= 0);
  257. stderr_buf[pos] = '\0';
  258. tt_str_op(expected_err,OP_EQ, stderr_buf);
  259. tt_int_op(strlen(expected_err),OP_EQ, pos);
  260. done:
  261. tor_process_handle_destroy(process_handle, 1);
  262. }
  263. static void
  264. test_util_spawn_background_partial_read(void *arg)
  265. {
  266. (void)arg;
  267. test_util_spawn_background_partial_read_impl(0);
  268. }
  269. static void
  270. test_util_spawn_background_exit_early(void *arg)
  271. {
  272. (void)arg;
  273. test_util_spawn_background_partial_read_impl(1);
  274. }
  275. static void
  276. test_util_spawn_background_waitpid_notify(void *arg)
  277. {
  278. int retval, exit_code;
  279. process_handle_t *process_handle=NULL;
  280. int status;
  281. int ms_timer;
  282. const char *argv[] = {TEST_CHILD, "--fast", NULL};
  283. (void) arg;
  284. #ifdef _WIN32
  285. status = tor_spawn_background(NULL, argv, NULL, &process_handle);
  286. #else
  287. status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
  288. #endif
  289. tt_int_op(status, OP_EQ, PROCESS_STATUS_RUNNING);
  290. tt_ptr_op(process_handle, OP_NE, NULL);
  291. /* We're not going to look at the stdout/stderr output this time. Instead,
  292. * we're testing whether notify_pending_waitpid_calbacks() can report the
  293. * process exit (on unix) and/or whether tor_get_exit_code() can notice it
  294. * (on windows) */
  295. #ifndef _WIN32
  296. ms_timer = 30*1000;
  297. tt_ptr_op(process_handle->waitpid_cb, OP_NE, NULL);
  298. while (process_handle->waitpid_cb && ms_timer > 0) {
  299. tor_sleep_msec(100);
  300. ms_timer -= 100;
  301. notify_pending_waitpid_callbacks();
  302. }
  303. tt_int_op(ms_timer, OP_GT, 0);
  304. tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
  305. #endif /* !defined(_WIN32) */
  306. ms_timer = 30*1000;
  307. while (((retval = tor_get_exit_code(process_handle, 0, &exit_code))
  308. == PROCESS_EXIT_RUNNING) && ms_timer > 0) {
  309. tor_sleep_msec(100);
  310. ms_timer -= 100;
  311. }
  312. tt_int_op(ms_timer, OP_GT, 0);
  313. tt_int_op(retval, OP_EQ, PROCESS_EXIT_EXITED);
  314. done:
  315. tor_process_handle_destroy(process_handle, 1);
  316. }
  317. #undef TEST_CHILD
  318. #undef EOL
  319. #undef MATCH_PROCESS_STATUS
  320. #ifndef _WIN32
  321. #undef PROCESS_STATUS_RUNNING_OR_NOTRUNNING
  322. #undef IS_RUNNING_OR_NOTRUNNING
  323. #endif
  324. #define UTIL_TEST(name, flags) \
  325. { #name, test_util_ ## name, flags, NULL, NULL }
  326. struct testcase_t slow_util_tests[] = {
  327. UTIL_TEST(spawn_background_ok, 0),
  328. UTIL_TEST(spawn_background_fail, 0),
  329. UTIL_TEST(spawn_background_partial_read, 0),
  330. UTIL_TEST(spawn_background_exit_early, 0),
  331. UTIL_TEST(spawn_background_waitpid_notify, 0),
  332. END_OF_TESTCASES
  333. };