exception.d 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. /**
  2. The exception module defines all system-level exceptions and provides a
  3. mechanism to alter system-level error handling.
  4. Copyright: Copyright Sean Kelly 2005 - 2013.
  5. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
  6. Authors: Sean Kelly and $(HTTP jmdavisprog.com, Jonathan M Davis)
  7. Source: $(DRUNTIMESRC core/_exception.d)
  8. */
  9. module core.exception;
  10. // Compiler lowers final switch default case to this (which is a runtime error)
  11. void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
  12. {
  13. // Consider making this a compile time check.
  14. version (D_Exceptions)
  15. throw staticError!SwitchError(file, line, null);
  16. else
  17. assert(0, "No appropriate switch clause found");
  18. }
  19. version (D_BetterC)
  20. {
  21. // When compiling with -betterC we use template functions so if they are
  22. // used the bodies are copied into the user's program so there is no need
  23. // for the D runtime during linking.
  24. // In the future we might want to convert all functions in this module to
  25. // templates even for ordinary builds instead of providing them as an
  26. // extern(C) library.
  27. void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
  28. {
  29. assert(0, "Memory allocation failed");
  30. }
  31. alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
  32. void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
  33. {
  34. assert(0, "Invalid memory operation");
  35. }
  36. }
  37. else:
  38. /**
  39. * Thrown on a range error.
  40. */
  41. class RangeError : Error
  42. {
  43. this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
  44. {
  45. super( "Range violation", file, line, next );
  46. }
  47. protected this( string msg, string file, size_t line, Throwable next = null ) @nogc nothrow pure @safe
  48. {
  49. super( msg, file, line, next );
  50. }
  51. }
  52. unittest
  53. {
  54. {
  55. auto re = new RangeError();
  56. assert(re.file == __FILE__);
  57. assert(re.line == __LINE__ - 2);
  58. assert(re.next is null);
  59. assert(re.msg == "Range violation");
  60. }
  61. {
  62. auto re = new RangeError("hello", 42, new Exception("It's an Exception!"));
  63. assert(re.file == "hello");
  64. assert(re.line == 42);
  65. assert(re.next !is null);
  66. assert(re.msg == "Range violation");
  67. }
  68. }
  69. /**
  70. * Thrown when an out of bounds array index is accessed.
  71. */
  72. class ArrayIndexError : RangeError
  73. {
  74. /// Index into array
  75. const size_t index;
  76. /// Length of indexed array
  77. const size_t length;
  78. // Buffer to avoid GC allocations
  79. private immutable char[100] msgBuf = '\0';
  80. this(size_t index, size_t length, string file = __FILE__,
  81. size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
  82. {
  83. this.index = index;
  84. this.length = length;
  85. // Constructing the message is a bit clumsy:
  86. // It's essentially `printf("index [%zu] is out of bounds for array of length [%zu]", index, length)`,
  87. // but even `snprintf` isn't `pure`.
  88. // Also string concatenation isn't `@nogc`, and casting to/from immutable isn't `@safe`
  89. import core.internal.string : unsignedToTempString;
  90. char[msgBuf.length] buf = void;
  91. char[20] tmpBuf = void;
  92. char[] sink = buf[];
  93. sink.rangeMsgPut("index [");
  94. sink.rangeMsgPut(unsignedToTempString!10(index, tmpBuf));
  95. sink.rangeMsgPut("] is out of bounds for array of length ");
  96. sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
  97. this.msgBuf = buf;
  98. super(msgBuf[0..$-sink.length], file, line, next);
  99. }
  100. }
  101. @safe pure unittest
  102. {
  103. assert(new ArrayIndexError(900, 700).msg == "index [900] is out of bounds for array of length 700");
  104. // Ensure msg buffer doesn't overflow on large numbers
  105. assert(new ArrayIndexError(size_t.max, size_t.max-1).msg);
  106. }
  107. unittest
  108. {
  109. try
  110. {
  111. _d_arraybounds_indexp("test", 400, 9, 3);
  112. assert(0, "no ArrayIndexError thrown");
  113. }
  114. catch (ArrayIndexError re)
  115. {
  116. assert(re.file == "test");
  117. assert(re.line == 400);
  118. assert(re.index == 9);
  119. assert(re.length == 3);
  120. }
  121. }
  122. /**
  123. * Thrown when an out of bounds array slice is created
  124. */
  125. class ArraySliceError : RangeError
  126. {
  127. /// Lower/upper bound passed to slice: `array[lower .. upper]`
  128. const size_t lower, upper;
  129. /// Length of sliced array
  130. const size_t length;
  131. private immutable char[120] msgBuf = '\0';
  132. this(size_t lower, size_t upper, size_t length, string file = __FILE__,
  133. size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
  134. {
  135. this.lower = lower;
  136. this.upper = upper;
  137. this.length = length;
  138. // Constructing the message is a bit clumsy for the same reasons as ArrayIndexError
  139. import core.internal.string : unsignedToTempString;
  140. char[msgBuf.length] buf = void;
  141. char[20] tmpBuf = void;
  142. char[] sink = buf;
  143. sink.rangeMsgPut("slice [");
  144. sink.rangeMsgPut(unsignedToTempString!10(lower, tmpBuf));
  145. sink.rangeMsgPut(" .. ");
  146. sink.rangeMsgPut(unsignedToTempString!10(upper, tmpBuf));
  147. sink.rangeMsgPut("] ");
  148. if (lower > upper)
  149. {
  150. sink.rangeMsgPut("has a larger lower index than upper index");
  151. }
  152. else
  153. {
  154. sink.rangeMsgPut("extends past source array of length ");
  155. sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
  156. }
  157. this.msgBuf = buf;
  158. super(msgBuf[0..$-sink.length], file, line, next);
  159. }
  160. }
  161. @safe pure unittest
  162. {
  163. assert(new ArraySliceError(40, 80, 20).msg == "slice [40 .. 80] extends past source array of length 20");
  164. assert(new ArraySliceError(90, 70, 20).msg == "slice [90 .. 70] has a larger lower index than upper index");
  165. // Ensure msg buffer doesn't overflow on large numbers
  166. assert(new ArraySliceError(size_t.max, size_t.max, size_t.max-1).msg);
  167. }
  168. unittest
  169. {
  170. try
  171. {
  172. _d_arraybounds_slicep("test", 400, 1, 7, 3);
  173. assert(0, "no ArraySliceError thrown");
  174. }
  175. catch (ArraySliceError re)
  176. {
  177. assert(re.file == "test");
  178. assert(re.line == 400);
  179. assert(re.lower == 1);
  180. assert(re.upper == 7);
  181. assert(re.length == 3);
  182. }
  183. }
  184. /// Mini `std.range.primitives: put` for constructor of ArraySliceError / ArrayIndexError
  185. private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure @safe
  186. {
  187. assert(r.length >= e.length); // don't throw ArraySliceError inside ArrayIndexError ctor
  188. r[0 .. e.length] = e[];
  189. r = r[e.length .. $];
  190. }
  191. /**
  192. * Thrown on an assert error.
  193. */
  194. class AssertError : Error
  195. {
  196. @safe pure nothrow this( string file, size_t line )
  197. {
  198. this(cast(Throwable)null, file, line);
  199. }
  200. @safe pure nothrow this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
  201. {
  202. this( "Assertion failure", file, line, next);
  203. }
  204. @safe pure nothrow this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
  205. {
  206. super( msg, file, line, next );
  207. }
  208. }
  209. unittest
  210. {
  211. {
  212. auto ae = new AssertError("hello", 42);
  213. assert(ae.file == "hello");
  214. assert(ae.line == 42);
  215. assert(ae.next is null);
  216. assert(ae.msg == "Assertion failure");
  217. }
  218. {
  219. auto ae = new AssertError(new Exception("It's an Exception!"));
  220. assert(ae.file == __FILE__);
  221. assert(ae.line == __LINE__ - 2);
  222. assert(ae.next !is null);
  223. assert(ae.msg == "Assertion failure");
  224. }
  225. {
  226. auto ae = new AssertError(new Exception("It's an Exception!"), "hello", 42);
  227. assert(ae.file == "hello");
  228. assert(ae.line == 42);
  229. assert(ae.next !is null);
  230. assert(ae.msg == "Assertion failure");
  231. }
  232. {
  233. auto ae = new AssertError("msg");
  234. assert(ae.file == __FILE__);
  235. assert(ae.line == __LINE__ - 2);
  236. assert(ae.next is null);
  237. assert(ae.msg == "msg");
  238. }
  239. {
  240. auto ae = new AssertError("msg", "hello", 42);
  241. assert(ae.file == "hello");
  242. assert(ae.line == 42);
  243. assert(ae.next is null);
  244. assert(ae.msg == "msg");
  245. }
  246. {
  247. auto ae = new AssertError("msg", "hello", 42, new Exception("It's an Exception!"));
  248. assert(ae.file == "hello");
  249. assert(ae.line == 42);
  250. assert(ae.next !is null);
  251. assert(ae.msg == "msg");
  252. }
  253. }
  254. /**
  255. * Thrown on finalize error.
  256. */
  257. class FinalizeError : Error
  258. {
  259. TypeInfo info;
  260. this( TypeInfo ci, Throwable next, string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow @nogc
  261. {
  262. this(ci, file, line, next);
  263. }
  264. this( TypeInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
  265. {
  266. super( "Finalization error", file, line, next );
  267. super.info = SuppressTraceInfo.instance;
  268. info = ci;
  269. }
  270. override string toString() const @safe
  271. {
  272. return "An exception was thrown while finalizing an instance of " ~ info.toString();
  273. }
  274. }
  275. unittest
  276. {
  277. ClassInfo info = new ClassInfo;
  278. info.name = "testInfo";
  279. {
  280. auto fe = new FinalizeError(info);
  281. assert(fe.file == __FILE__);
  282. assert(fe.line == __LINE__ - 2);
  283. assert(fe.next is null);
  284. assert(fe.msg == "Finalization error");
  285. assert(fe.info == info);
  286. }
  287. {
  288. auto fe = new FinalizeError(info, new Exception("It's an Exception!"));
  289. assert(fe.file == __FILE__);
  290. assert(fe.line == __LINE__ - 2);
  291. assert(fe.next !is null);
  292. assert(fe.msg == "Finalization error");
  293. assert(fe.info == info);
  294. }
  295. {
  296. auto fe = new FinalizeError(info, "hello", 42);
  297. assert(fe.file == "hello");
  298. assert(fe.line == 42);
  299. assert(fe.next is null);
  300. assert(fe.msg == "Finalization error");
  301. assert(fe.info == info);
  302. }
  303. {
  304. auto fe = new FinalizeError(info, "hello", 42, new Exception("It's an Exception!"));
  305. assert(fe.file == "hello");
  306. assert(fe.line == 42);
  307. assert(fe.next !is null);
  308. assert(fe.msg == "Finalization error");
  309. assert(fe.info == info);
  310. }
  311. }
  312. /**
  313. * Thrown on an out of memory error.
  314. */
  315. class OutOfMemoryError : Error
  316. {
  317. this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
  318. {
  319. this(true, file, line, next);
  320. }
  321. this(bool trace, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
  322. {
  323. super("Memory allocation failed", file, line, next);
  324. if (!trace)
  325. this.info = SuppressTraceInfo.instance;
  326. }
  327. override string toString() const @trusted
  328. {
  329. return msg.length ? (cast()this).superToString() : "Memory allocation failed";
  330. }
  331. // kludge to call non-const super.toString
  332. private string superToString() @trusted
  333. {
  334. return super.toString();
  335. }
  336. }
  337. unittest
  338. {
  339. {
  340. auto oome = new OutOfMemoryError();
  341. assert(oome.file == __FILE__);
  342. assert(oome.line == __LINE__ - 2);
  343. assert(oome.next is null);
  344. assert(oome.msg == "Memory allocation failed");
  345. assert(oome.toString.length);
  346. }
  347. {
  348. auto oome = new OutOfMemoryError("hello", 42, new Exception("It's an Exception!"));
  349. assert(oome.file == "hello");
  350. assert(oome.line == 42);
  351. assert(oome.next !is null);
  352. assert(oome.msg == "Memory allocation failed");
  353. }
  354. }
  355. /**
  356. * Thrown on an invalid memory operation.
  357. *
  358. * An invalid memory operation error occurs in circumstances when the garbage
  359. * collector has detected an operation it cannot reliably handle. The default
  360. * D GC is not re-entrant, so this can happen due to allocations done from
  361. * within finalizers called during a garbage collection cycle.
  362. */
  363. class InvalidMemoryOperationError : Error
  364. {
  365. this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
  366. {
  367. super( "Invalid memory operation", file, line, next );
  368. this.info = SuppressTraceInfo.instance;
  369. }
  370. override string toString() const @trusted
  371. {
  372. return msg.length ? (cast()this).superToString() : "Invalid memory operation";
  373. }
  374. // kludge to call non-const super.toString
  375. private string superToString() @trusted
  376. {
  377. return super.toString();
  378. }
  379. }
  380. unittest
  381. {
  382. {
  383. auto oome = new InvalidMemoryOperationError();
  384. assert(oome.file == __FILE__);
  385. assert(oome.line == __LINE__ - 2);
  386. assert(oome.next is null);
  387. assert(oome.msg == "Invalid memory operation");
  388. assert(oome.toString.length);
  389. }
  390. {
  391. auto oome = new InvalidMemoryOperationError("hello", 42, new Exception("It's an Exception!"));
  392. assert(oome.file == "hello");
  393. assert(oome.line == 42);
  394. assert(oome.next !is null);
  395. assert(oome.msg == "Invalid memory operation");
  396. }
  397. }
  398. /**
  399. * Thrown on a configuration error.
  400. */
  401. class ForkError : Error
  402. {
  403. this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
  404. {
  405. super( "fork() failed", file, line, next );
  406. }
  407. }
  408. /**
  409. * Thrown on a switch error.
  410. */
  411. class SwitchError : Error
  412. {
  413. @safe pure nothrow @nogc this( string file = __FILE__, size_t line = __LINE__, Throwable next = null )
  414. {
  415. super( "No appropriate switch clause found", file, line, next );
  416. }
  417. }
  418. unittest
  419. {
  420. {
  421. auto se = new SwitchError();
  422. assert(se.file == __FILE__);
  423. assert(se.line == __LINE__ - 2);
  424. assert(se.next is null);
  425. assert(se.msg == "No appropriate switch clause found");
  426. }
  427. {
  428. auto se = new SwitchError("hello", 42, new Exception("It's an Exception!"));
  429. assert(se.file == "hello");
  430. assert(se.line == 42);
  431. assert(se.next !is null);
  432. assert(se.msg == "No appropriate switch clause found");
  433. }
  434. }
  435. /**
  436. * Thrown on a unicode conversion error.
  437. */
  438. class UnicodeException : Exception
  439. {
  440. size_t idx;
  441. this( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
  442. {
  443. super( msg, file, line, next );
  444. this.idx = idx;
  445. }
  446. }
  447. unittest
  448. {
  449. {
  450. auto ue = new UnicodeException("msg", 2);
  451. assert(ue.file == __FILE__);
  452. assert(ue.line == __LINE__ - 2);
  453. assert(ue.next is null);
  454. assert(ue.msg == "msg");
  455. assert(ue.idx == 2);
  456. }
  457. {
  458. auto ue = new UnicodeException("msg", 2, "hello", 42, new Exception("It's an Exception!"));
  459. assert(ue.file == "hello");
  460. assert(ue.line == 42);
  461. assert(ue.next !is null);
  462. assert(ue.msg == "msg");
  463. assert(ue.idx == 2);
  464. }
  465. }
  466. ///////////////////////////////////////////////////////////////////////////////
  467. // Overrides
  468. ///////////////////////////////////////////////////////////////////////////////
  469. // NOTE: One assert handler is used for all threads. Thread-local
  470. // behavior should occur within the handler itself. This delegate
  471. // is __gshared for now based on the assumption that it will only
  472. // set by the main thread during program initialization.
  473. private __gshared AssertHandler _assertHandler = null;
  474. /**
  475. Gets/sets assert hander. null means the default handler is used.
  476. */
  477. alias AssertHandler = void function(string file, size_t line, string msg) nothrow;
  478. /// ditto
  479. @property AssertHandler assertHandler() @trusted nothrow @nogc
  480. {
  481. return _assertHandler;
  482. }
  483. /// ditto
  484. @property void assertHandler(AssertHandler handler) @trusted nothrow @nogc
  485. {
  486. _assertHandler = handler;
  487. }
  488. ///////////////////////////////////////////////////////////////////////////////
  489. // Overridable Callbacks
  490. ///////////////////////////////////////////////////////////////////////////////
  491. /**
  492. * A callback for assert errors in D. The user-supplied assert handler will
  493. * be called if one has been supplied, otherwise an $(LREF AssertError) will be
  494. * thrown.
  495. *
  496. * Params:
  497. * file = The name of the file that signaled this error.
  498. * line = The line number on which this error occurred.
  499. */
  500. extern (C) void onAssertError( string file = __FILE__, size_t line = __LINE__ ) nothrow
  501. {
  502. if ( _assertHandler is null )
  503. throw staticError!AssertError(file, line);
  504. _assertHandler( file, line, null);
  505. }
  506. /**
  507. * A callback for assert errors in D. The user-supplied assert handler will
  508. * be called if one has been supplied, otherwise an $(LREF AssertError) will be
  509. * thrown.
  510. *
  511. * Params:
  512. * file = The name of the file that signaled this error.
  513. * line = The line number on which this error occurred.
  514. * msg = An error message supplied by the user.
  515. */
  516. extern (C) void onAssertErrorMsg( string file, size_t line, string msg ) nothrow
  517. {
  518. if ( _assertHandler is null )
  519. throw staticError!AssertError(msg, file, line);
  520. _assertHandler( file, line, msg );
  521. }
  522. /**
  523. * A callback for unittest errors in D. The user-supplied unittest handler
  524. * will be called if one has been supplied, otherwise the error will be
  525. * written to stderr.
  526. *
  527. * Params:
  528. * file = The name of the file that signaled this error.
  529. * line = The line number on which this error occurred.
  530. * msg = An error message supplied by the user.
  531. */
  532. extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothrow
  533. {
  534. onAssertErrorMsg( file, line, msg );
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////
  537. // Internal Error Callbacks
  538. ///////////////////////////////////////////////////////////////////////////////
  539. /**
  540. * A callback for general array bounds errors in D. A $(LREF RangeError) will be thrown.
  541. *
  542. * Params:
  543. * file = The name of the file that signaled this error.
  544. * line = The line number on which this error occurred.
  545. *
  546. * Throws:
  547. * $(LREF RangeError).
  548. */
  549. extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
  550. {
  551. throw staticError!RangeError(file, line, null);
  552. }
  553. /**
  554. * A callback for array slice out of bounds errors in D.
  555. *
  556. * Params:
  557. * lower = the lower bound of the index passed of a slice
  558. * upper = the upper bound of the index passed of a slice or the index if not a slice
  559. * length = length of the array
  560. * file = The name of the file that signaled this error.
  561. * line = The line number on which this error occurred.
  562. *
  563. * Throws:
  564. * $(LREF ArraySliceError).
  565. */
  566. extern (C) void onArraySliceError( size_t lower = 0, size_t upper = 0, size_t length = 0,
  567. string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
  568. {
  569. throw staticError!ArraySliceError(lower, upper, length, file, line, null);
  570. }
  571. /**
  572. * A callback for array index out of bounds errors in D.
  573. *
  574. * Params:
  575. * index = index in the array
  576. * length = length of the array
  577. * file = The name of the file that signaled this error.
  578. * line = The line number on which this error occurred.
  579. *
  580. * Throws:
  581. * $(LREF ArrayIndexError).
  582. */
  583. extern (C) void onArrayIndexError( size_t index = 0, size_t length = 0,
  584. string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
  585. {
  586. throw staticError!ArrayIndexError(index, length, file, line, null);
  587. }
  588. /**
  589. * A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown.
  590. *
  591. * Params:
  592. * info = The TypeInfo instance for the object that failed finalization.
  593. * e = The exception thrown during finalization.
  594. * file = The name of the file that signaled this error.
  595. * line = The line number on which this error occurred.
  596. *
  597. * Throws:
  598. * $(LREF FinalizeError).
  599. */
  600. extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
  601. {
  602. // This error is thrown during a garbage collection, so no allocation must occur while
  603. // generating this object. So we use a preallocated instance
  604. throw staticError!FinalizeError(info, e, file, line);
  605. }
  606. /**
  607. * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be
  608. * thrown.
  609. *
  610. * Throws:
  611. * $(LREF OutOfMemoryError).
  612. */
  613. extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
  614. {
  615. // NOTE: Since an out of memory condition exists, no allocation must occur
  616. // while generating this object.
  617. throw staticError!OutOfMemoryError();
  618. }
  619. extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
  620. {
  621. // suppress stacktrace until they are @nogc
  622. throw staticError!OutOfMemoryError(false);
  623. }
  624. /**
  625. * A callback for invalid memory operations in D. An
  626. * $(LREF InvalidMemoryOperationError) will be thrown.
  627. *
  628. * Throws:
  629. * $(LREF InvalidMemoryOperationError).
  630. */
  631. extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
  632. {
  633. // The same restriction applies as for onOutOfMemoryError. The GC is in an
  634. // undefined state, thus no allocation must occur while generating this object.
  635. throw staticError!InvalidMemoryOperationError();
  636. }
  637. /**
  638. * A callback for errors in the case of a failed fork in D. A $(LREF ForkError) will be thrown.
  639. *
  640. * Params:
  641. * file = The name of the file that signaled this error.
  642. * line = The line number on which this error occurred.
  643. *
  644. * Throws:
  645. * $(LREF ConfigurationError).
  646. */
  647. extern (C) void onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
  648. {
  649. throw staticError!ForkError( file, line, null );
  650. }
  651. /**
  652. * A callback for unicode errors in D. A $(LREF UnicodeException) will be thrown.
  653. *
  654. * Params:
  655. * msg = Information about the error.
  656. * idx = String index where this error was detected.
  657. * file = The name of the file that signaled this error.
  658. * line = The line number on which this error occurred.
  659. *
  660. * Throws:
  661. * $(LREF UnicodeException).
  662. */
  663. extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure
  664. {
  665. throw new UnicodeException( msg, idx, file, line );
  666. }
  667. /***********************************
  668. * These functions must be defined for any D program linked
  669. * against this library.
  670. */
  671. /+
  672. extern (C) void onAssertError(string file, size_t line);
  673. extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
  674. extern (C) void onUnittestErrorMsg(string file, size_t line, string msg);
  675. extern (C) void onRangeError(string file, size_t line);
  676. extern (C) void onHiddenFuncError(Object o);
  677. +/
  678. /***********************************
  679. * Function calls to these are generated by the compiler and inserted into
  680. * the object code.
  681. */
  682. extern (C)
  683. {
  684. /* One of these three is called upon an assert() fail.
  685. */
  686. void _d_assertp(immutable(char)* file, uint line)
  687. {
  688. import core.stdc.string : strlen;
  689. onAssertError(file[0 .. strlen(file)], line);
  690. }
  691. void _d_assert_msg(string msg, string file, uint line)
  692. {
  693. onAssertErrorMsg(file, line, msg);
  694. }
  695. void _d_assert(string file, uint line)
  696. {
  697. onAssertError(file, line);
  698. }
  699. /* One of these three is called upon an assert() fail inside of a unittest block
  700. */
  701. void _d_unittestp(immutable(char)* file, uint line)
  702. {
  703. import core.stdc.string : strlen;
  704. _d_unittest(file[0 .. strlen(file)], line);
  705. }
  706. void _d_unittest_msg(string msg, string file, uint line)
  707. {
  708. onUnittestErrorMsg(file, line, msg);
  709. }
  710. void _d_unittest(string file, uint line)
  711. {
  712. _d_unittest_msg("unittest failure", file, line);
  713. }
  714. /// Called when an invalid array index/slice or associative array key is accessed
  715. void _d_arrayboundsp(immutable(char*) file, uint line)
  716. {
  717. import core.stdc.string : strlen;
  718. onRangeError(file[0 .. strlen(file)], line);
  719. }
  720. /// ditto
  721. void _d_arraybounds(string file, uint line)
  722. {
  723. onRangeError(file, line);
  724. }
  725. /// Called when an out of range slice of an array is created
  726. void _d_arraybounds_slicep(immutable(char*) file, uint line, size_t lower, size_t upper, size_t length)
  727. {
  728. import core.stdc.string : strlen;
  729. onArraySliceError(lower, upper, length, file[0 .. strlen(file)], line);
  730. }
  731. /// ditto
  732. void _d_arraybounds_slice(string file, uint line, size_t lower, size_t upper, size_t length)
  733. {
  734. onArraySliceError(lower, upper, length, file, line);
  735. }
  736. /// Called when an out of range array index is accessed
  737. void _d_arraybounds_indexp(immutable(char*) file, uint line, size_t index, size_t length)
  738. {
  739. import core.stdc.string : strlen;
  740. onArrayIndexError(index, length, file[0 .. strlen(file)], line);
  741. }
  742. /// ditto
  743. void _d_arraybounds_index(string file, uint line, size_t index, size_t length)
  744. {
  745. onArrayIndexError(index, length, file, line);
  746. }
  747. }
  748. // TLS storage shared for all errors, chaining might create circular reference
  749. private align(2 * size_t.sizeof) void[256] _store;
  750. // only Errors for now as those are rarely chained
  751. private T staticError(T, Args...)(auto ref Args args)
  752. if (is(T : Error))
  753. {
  754. // pure hack, what we actually need is @noreturn and allow to call that in pure functions
  755. static T get()
  756. {
  757. static assert(__traits(classInstanceSize, T) <= _store.length,
  758. T.stringof ~ " is too large for staticError()");
  759. return cast(T) _store.ptr;
  760. }
  761. auto res = (cast(T function() @trusted pure nothrow @nogc) &get)();
  762. import core.lifetime : emplace;
  763. emplace(res, args);
  764. return res;
  765. }
  766. // Suppress traceinfo generation when the GC cannot be used. Workaround for
  767. // Bugzilla 14993. We should make stack traces @nogc instead.
  768. package class SuppressTraceInfo : Throwable.TraceInfo
  769. {
  770. override int opApply(scope int delegate(ref const(char[]))) const { return 0; }
  771. override int opApply(scope int delegate(ref size_t, ref const(char[]))) const { return 0; }
  772. override string toString() const { return null; }
  773. static SuppressTraceInfo instance() @trusted @nogc pure nothrow
  774. {
  775. static immutable SuppressTraceInfo it = new SuppressTraceInfo;
  776. return cast(SuppressTraceInfo)it;
  777. }
  778. }