test_cxx.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include <vector>
  2. #include <numeric>
  3. #include <stdexcept>
  4. #include <string>
  5. #include "unity.h"
  6. #include "esp_log.h"
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "freertos/semphr.h"
  10. #include "soc/soc.h"
  11. TEST_CASE("can use new and delete", "[cxx]")
  12. {
  13. int* int_p = new int(10);
  14. delete int_p;
  15. int* int_array = new int[10];
  16. delete[] int_array;
  17. }
  18. class Base
  19. {
  20. public:
  21. virtual ~Base() {}
  22. virtual void foo() = 0;
  23. };
  24. class Derived : public Base
  25. {
  26. public:
  27. virtual void foo() { }
  28. };
  29. TEST_CASE("can call virtual functions", "[cxx]")
  30. {
  31. Derived d;
  32. Base& b = static_cast<Base&>(d);
  33. b.foo();
  34. }
  35. TEST_CASE("can use std::vector", "[cxx]")
  36. {
  37. std::vector<int> v(10, 1);
  38. v[0] = 42;
  39. TEST_ASSERT_EQUAL(51, std::accumulate(std::begin(v), std::end(v), 0));
  40. }
  41. /* Note: When first exception (in system) is thrown this test produces memory leaks report (~300 bytes):
  42. - 392 bytes (can vary) as libunwind allocates memory to keep stack frames info to handle exceptions.
  43. This info is kept until global destructors are called by __do_global_dtors_aux()
  44. - 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
  45. - 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
  46. - 88 bytes are allocated by pthread_setspecific() to init internal lock
  47. - some more memory...
  48. */
  49. #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
  50. TEST_CASE("c++ exceptions work", "[cxx] [exceptions] [leaks=300]")
  51. {
  52. int thrown_value;
  53. try {
  54. throw 20;
  55. } catch (int e) {
  56. thrown_value = e;
  57. }
  58. TEST_ASSERT_EQUAL(20, thrown_value);
  59. printf("OK?\n");
  60. }
  61. TEST_CASE("c++ bool exception", "[cxx] [exceptions] [leaks=300]")
  62. {
  63. bool thrown_value = false;
  64. try {
  65. throw true;
  66. } catch (bool e) {
  67. thrown_value = e;
  68. }
  69. TEST_ASSERT_EQUAL(true, thrown_value);
  70. printf("OK?\n");
  71. }
  72. TEST_CASE("c++ void exception", "[cxx] [exceptions] [leaks=300]")
  73. {
  74. void* thrown_value = 0;
  75. try {
  76. throw (void*) 47;
  77. } catch (void* e) {
  78. thrown_value = e;
  79. }
  80. TEST_ASSERT_EQUAL(47, thrown_value);
  81. printf("OK?\n");
  82. }
  83. TEST_CASE("c++ uint64_t exception", "[cxx] [exceptions] [leaks=300]")
  84. {
  85. uint64_t thrown_value = 0;
  86. try {
  87. throw (uint64_t) 47;
  88. } catch (uint64_t e) {
  89. thrown_value = e;
  90. }
  91. TEST_ASSERT_EQUAL(47, thrown_value);
  92. printf("OK?\n");
  93. }
  94. TEST_CASE("c++ char exception", "[cxx] [exceptions] [leaks=300]")
  95. {
  96. char thrown_value = '0';
  97. try {
  98. throw '/';
  99. } catch (char e) {
  100. thrown_value = e;
  101. }
  102. TEST_ASSERT_EQUAL('/', thrown_value);
  103. printf("OK?\n");
  104. }
  105. TEST_CASE("c++ wchar exception", "[cxx] [exceptions] [leaks=300]")
  106. {
  107. wchar_t thrown_value = 0;
  108. try {
  109. throw (wchar_t) 47;
  110. } catch (wchar_t e) {
  111. thrown_value = e;
  112. }
  113. TEST_ASSERT_EQUAL((wchar_t) 47, thrown_value);
  114. printf("OK?\n");
  115. }
  116. TEST_CASE("c++ float exception", "[cxx] [exceptions] [leaks=300]")
  117. {
  118. float thrown_value = 0;
  119. try {
  120. throw 23.5f;
  121. } catch (float e) {
  122. thrown_value = e;
  123. }
  124. TEST_ASSERT_EQUAL(23.5, thrown_value);
  125. printf("OK?\n");
  126. }
  127. TEST_CASE("c++ double exception", "[cxx] [exceptions] [leaks=300]")
  128. {
  129. double thrown_value = 0;
  130. try {
  131. throw 23.5d;
  132. } catch (double e) {
  133. thrown_value = e;
  134. }
  135. TEST_ASSERT_EQUAL(23.5d, thrown_value);
  136. printf("OK?\n");
  137. }
  138. TEST_CASE("c++ const char* exception", "[cxx] [exceptions] [leaks=300]")
  139. {
  140. const char *thrown_value = 0;
  141. try {
  142. throw "Hi :)";
  143. } catch (const char *e) {
  144. thrown_value = e;
  145. }
  146. TEST_ASSERT_EQUAL_STRING("Hi :)", thrown_value);
  147. printf("OK?\n");
  148. }
  149. struct NonExcTypeThrowee {
  150. int value;
  151. public:
  152. NonExcTypeThrowee(int value) : value(value) { }
  153. };
  154. TEST_CASE("c++ any class exception", "[cxx] [exceptions] [leaks=300]")
  155. {
  156. int thrown_value = 0;
  157. try {
  158. throw NonExcTypeThrowee(47);
  159. } catch (NonExcTypeThrowee &e) {
  160. thrown_value = e.value;
  161. }
  162. TEST_ASSERT_EQUAL(47, thrown_value);
  163. printf("OK?\n");
  164. }
  165. struct ExcTypeThrowee : public std::exception {
  166. int value;
  167. public:
  168. ExcTypeThrowee(int value) : value(value) { }
  169. };
  170. TEST_CASE("c++ std::exception child", "[cxx] [exceptions] [leaks=300]")
  171. {
  172. int thrown_value = 0;
  173. try {
  174. throw ExcTypeThrowee(47);
  175. } catch (ExcTypeThrowee &e) {
  176. thrown_value = e.value;
  177. }
  178. TEST_ASSERT_EQUAL(47, thrown_value);
  179. printf("OK?\n");
  180. }
  181. TEST_CASE("c++ exceptions emergency pool", "[cxx] [exceptions] [ignore] [leaks=300]")
  182. {
  183. /* Note: When first exception (in system) is thrown this test produces memory leaks report (~500 bytes):
  184. - 392 bytes (can vary) as libunwind allocates memory to keep stack frames info to handle exceptions.
  185. This info is kept until global destructors are called by __do_global_dtors_aux()
  186. - 8 bytes are allocated by __cxa_get_globals() to keep __cxa_eh_globals
  187. - 16 bytes are allocated by pthread_setspecific() which is called by __cxa_get_globals() to init TLS var for __cxa_eh_globals
  188. - 88 bytes are allocated by pthread_setspecific() to init internal lock
  189. */
  190. void **p, **pprev = NULL;
  191. int thrown_value = 0;
  192. // throw first exception to ensure that all initial allocations are made
  193. try
  194. {
  195. throw 33;
  196. }
  197. catch (int e)
  198. {
  199. thrown_value = e;
  200. }
  201. TEST_ASSERT_EQUAL(33, thrown_value);
  202. // consume all dynamic memory
  203. while ((p = (void **)malloc(sizeof(void *)))) {
  204. if (pprev) {
  205. *p = pprev;
  206. } else {
  207. *p = NULL;
  208. }
  209. pprev = p;
  210. }
  211. try
  212. {
  213. throw 20;
  214. }
  215. catch (int e)
  216. {
  217. thrown_value = e;
  218. printf("Got exception %d\n", thrown_value);
  219. }
  220. #if CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE > 0
  221. // free all memory
  222. while (pprev) {
  223. p = (void **)(*pprev);
  224. free(pprev);
  225. pprev = p;
  226. }
  227. TEST_ASSERT_EQUAL(20, thrown_value);
  228. #else
  229. // if emergency pool is disabled we should never get here,
  230. // expect abort() due to lack of memory for new exception
  231. TEST_ASSERT_TRUE(0 == 1);
  232. #endif
  233. }
  234. #else // !CONFIG_COMPILER_CXX_EXCEPTIONS
  235. TEST_CASE("std::out_of_range exception when -fno-exceptions", "[cxx][reset=abort,SW_CPU_RESET]")
  236. {
  237. std::vector<int> v(10);
  238. v.at(20) = 42;
  239. TEST_FAIL_MESSAGE("Unreachable because we are aborted on the line above");
  240. }
  241. TEST_CASE("std::bad_alloc exception when -fno-exceptions", "[cxx][reset=abort,SW_CPU_RESET]")
  242. {
  243. std::string s = std::string(2000000000, 'a');
  244. (void)s;
  245. TEST_FAIL_MESSAGE("Unreachable because we are aborted on the line above");
  246. }
  247. #endif
  248. /* These test cases pull a lot of code from libstdc++ and are disabled for now
  249. */
  250. #if 0
  251. #include <iostream>
  252. #include <functional>
  253. TEST_CASE("can use iostreams", "[cxx]")
  254. {
  255. std::cout << "hello world";
  256. }
  257. TEST_CASE("can call std::function and bind", "[cxx]")
  258. {
  259. int outer = 1;
  260. std::function<int(int)> fn = [&outer](int x) -> int {
  261. return x + outer;
  262. };
  263. outer = 5;
  264. TEST_ASSERT_EQUAL(6, fn(1));
  265. auto bound = std::bind(fn, outer);
  266. outer = 10;
  267. TEST_ASSERT_EQUAL(15, bound());
  268. }
  269. #endif