altstack.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /* Licensed under Apache License v2.0 - see LICENSE file for details */
  2. #ifndef CCAN_ALTSTACK_H
  3. #define CCAN_ALTSTACK_H
  4. #include "config.h"
  5. #if ! __x86_64__
  6. #error "This code expects the AMD64 ABI, but __x86_64__ is false."
  7. #endif
  8. #include <stddef.h>
  9. #include <sys/resource.h>
  10. #define ALTSTACK_ERR_MAXLEN 128
  11. /**
  12. * altstack - run a function with a dedicated stack, and then release the memory
  13. * @max: the maximum size of the new stack
  14. * @fn: a function to run
  15. * @arg: an argument passed to fn
  16. * @out: where to store the return of fn, optional
  17. *
  18. * rlimit is set to @max, and an anonymous noreserve mapping is made.
  19. * A jump buffer is setup and a signal handler established for SIGSEGV.
  20. * The rsp register is set to the mapped address, with the old rsp value
  21. * pushed onto the new stack. The provided @fn is called, with @arg as
  22. * its only argument, from non-stack addresses. Once @fn returns,
  23. * rsp is popped off the stack. If @out is non-null, it gets the return
  24. * value from @fn. The region is unmapped and the other changes undone.
  25. *
  26. * Error messages are appended to a buffer available via altstack_geterr()
  27. * and altstack_perror(). errno is set by the failing call, or set to
  28. * EOVERFLOW in case SIGSEGV is caught.
  29. *
  30. * altstack() uses thread-local storage, and should not be nested.
  31. *
  32. * Example:
  33. * // permit recursion depth over a million
  34. * // a contrived example! (-O2 replaces the recursion with a loop)
  35. * #include <assert.h>
  36. * #include <stdio.h>
  37. * #include <stdlib.h>
  38. * #include <ccan/altstack/altstack.h>
  39. *
  40. * unsigned depth;
  41. *
  42. * static void dn(unsigned long i)
  43. * {
  44. * depth++;
  45. * if (i) dn(--i);
  46. * }
  47. *
  48. * static void *wrap(void *i)
  49. * {
  50. * dn((unsigned long) i);
  51. * return 0;
  52. * }
  53. *
  54. * #define MiB (1024UL*1024UL)
  55. * int main(int argc, char *argv[])
  56. * {
  57. * unsigned long n;
  58. * assert(argc == 2);
  59. * n = strtoul(argv[1], 0, 0);
  60. *
  61. * if (altstack(32*MiB, wrap, (void *) n, 0) != 0)
  62. * altstack_perror();
  63. *
  64. * printf("%d\n", depth);
  65. *
  66. * return 0;
  67. * }
  68. *
  69. * Returns: -1 on error; 0 on success; 1 on error after @fn returns
  70. */
  71. int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out);
  72. /**
  73. * altstack_perror - print error messages to stderr
  74. */
  75. void altstack_perror(void);
  76. /**
  77. * altstack_geterr - return the error buffer
  78. *
  79. * The error buffer is static thread-local storage.
  80. * The buffer is reset with each altstack() call.
  81. *
  82. * Returns: pointer to the error buffer
  83. */
  84. char *altstack_geterr(void);
  85. /**
  86. * altstack_used - return amount of stack used
  87. *
  88. * This captures the current rsp value and returns
  89. * the difference from the initial rsp value.
  90. *
  91. * Note: this can be used with any stack, including the original.
  92. * When using with a non-altstack stack, call altstack_rsp_save()
  93. * as early as possible to establish the initial value.
  94. *
  95. * Returns: difference of rsp values
  96. */
  97. ptrdiff_t altstack_used(void);
  98. /**
  99. * altstack_max - return usable stack size
  100. *
  101. * Returns: max value from altstack() call
  102. */
  103. rlim_t altstack_max(void);
  104. /**
  105. * altstack_remn - return amount of stack remaining
  106. *
  107. * Returns: altstack_max() minus altstack_used()
  108. */
  109. #define altstack_remn() (altstack_max() - altstack_used())
  110. /**
  111. * altstack_rsp_save - set initial rsp value
  112. *
  113. * Capture the current value of rsp for future altstack_used()
  114. * calculations. altstack() also saves the initial rsp, so
  115. * this should only be used in non-altstack contexts.
  116. */
  117. void altstack_rsp_save(void);
  118. #endif