error.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. // Copyright (C) 2004-2024 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include <assert.h>
  24. #include <stdarg.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #ifdef _WIN32
  30. #ifndef NDEBUG
  31. #define USE_OUTPUT_DEBUG_STRING
  32. #include <windows.h>
  33. #endif
  34. #endif
  35. #ifdef __ANDROID__
  36. #define USE_ANDROID_LOG
  37. #include <android/log.h>
  38. #endif
  39. void fz_default_error_callback(void *user, const char *message)
  40. {
  41. /* TODO: send errcode and format it here instead of in fz_report_error */
  42. fputs(message, stderr);
  43. fputc('\n', stderr);
  44. #ifdef USE_OUTPUT_DEBUG_STRING
  45. OutputDebugStringA(message);
  46. OutputDebugStringA("\n");
  47. #endif
  48. #ifdef USE_ANDROID_LOG
  49. __android_log_print(ANDROID_LOG_ERROR, "libmupdf", "%s", message);
  50. #endif
  51. }
  52. void fz_default_warning_callback(void *user, const char *message)
  53. {
  54. fprintf(stderr, "warning: %s\n", message);
  55. #ifdef USE_OUTPUT_DEBUG_STRING
  56. OutputDebugStringA("warning: ");
  57. OutputDebugStringA(message);
  58. OutputDebugStringA("\n");
  59. #endif
  60. #ifdef USE_ANDROID_LOG
  61. __android_log_print(ANDROID_LOG_WARN, "libmupdf", "%s", message);
  62. #endif
  63. }
  64. /* Warning context */
  65. void fz_set_warning_callback(fz_context *ctx, fz_warning_cb *warning_cb, void *user)
  66. {
  67. ctx->warn.print_user = user;
  68. ctx->warn.print = warning_cb;
  69. }
  70. fz_warning_cb *fz_warning_callback(fz_context *ctx, void **user)
  71. {
  72. if (user)
  73. *user = ctx->warn.print_user;
  74. return ctx->warn.print;
  75. }
  76. void fz_var_imp(void *var)
  77. {
  78. /* Do nothing */
  79. }
  80. void fz_flush_warnings(fz_context *ctx)
  81. {
  82. if (ctx->warn.count > 1)
  83. {
  84. char buf[50];
  85. fz_snprintf(buf, sizeof buf, "... repeated %d times...", ctx->warn.count);
  86. if (ctx->warn.print)
  87. ctx->warn.print(ctx->warn.print_user, buf);
  88. }
  89. ctx->warn.message[0] = 0;
  90. ctx->warn.count = 0;
  91. }
  92. void (fz_vwarn)(fz_context *ctx, const char *fmt, va_list ap)
  93. {
  94. char buf[sizeof ctx->warn.message];
  95. fz_vsnprintf(buf, sizeof buf, fmt, ap);
  96. buf[sizeof(buf) - 1] = 0;
  97. if (!strcmp(buf, ctx->warn.message))
  98. {
  99. ctx->warn.count++;
  100. }
  101. else
  102. {
  103. fz_flush_warnings(ctx);
  104. if (ctx->warn.print)
  105. ctx->warn.print(ctx->warn.print_user, buf);
  106. fz_strlcpy(ctx->warn.message, buf, sizeof ctx->warn.message);
  107. ctx->warn.count = 1;
  108. }
  109. }
  110. void (fz_warn)(fz_context *ctx, const char *fmt, ...)
  111. {
  112. va_list ap;
  113. va_start(ap, fmt);
  114. fz_vwarn(ctx, fmt, ap);
  115. va_end(ap);
  116. }
  117. #if FZ_VERBOSE_EXCEPTIONS
  118. void fz_vwarnFL(fz_context *ctx, const char *file, int line, const char *fmt, va_list ap)
  119. {
  120. char buf[sizeof ctx->warn.message];
  121. fz_vsnprintf(buf, sizeof buf, fmt, ap);
  122. buf[sizeof(buf) - 1] = 0;
  123. if (!strcmp(buf, ctx->warn.message))
  124. {
  125. ctx->warn.count++;
  126. }
  127. else
  128. {
  129. fz_flush_warnings(ctx);
  130. if (ctx->warn.print)
  131. ctx->warn.print(ctx->warn.print_user, buf);
  132. fz_strlcpy(ctx->warn.message, buf, sizeof ctx->warn.message);
  133. ctx->warn.count = 1;
  134. }
  135. }
  136. void fz_warnFL(fz_context *ctx, const char *file, int line, const char *fmt, ...)
  137. {
  138. va_list ap;
  139. va_start(ap, fmt);
  140. fz_vwarnFL(ctx, file, line, fmt, ap);
  141. va_end(ap);
  142. }
  143. #endif
  144. /* Error context */
  145. void fz_set_error_callback(fz_context *ctx, fz_error_cb *error_cb, void *user)
  146. {
  147. ctx->error.print_user = user;
  148. ctx->error.print = error_cb;
  149. }
  150. fz_error_cb *fz_error_callback(fz_context *ctx, void **user)
  151. {
  152. if (user)
  153. *user = ctx->error.print_user;
  154. return ctx->error.print;
  155. }
  156. /* When we first setjmp, state is set to 0. Whenever we throw, we add 2 to
  157. * this state. Whenever we enter the always block, we add 1.
  158. *
  159. * fz_push_try sets state to 0.
  160. * If (fz_throw called within fz_try)
  161. * fz_throw makes state = 2.
  162. * If (no always block present)
  163. * enter catch region with state = 2. OK.
  164. * else
  165. * fz_always entered as state < 3; Makes state = 3;
  166. * if (fz_throw called within fz_always)
  167. * fz_throw makes state = 5
  168. * fz_always is not reentered.
  169. * catch region entered with state = 5. OK.
  170. * else
  171. * catch region entered with state = 3. OK
  172. * else
  173. * if (no always block present)
  174. * catch region not entered as state = 0. OK.
  175. * else
  176. * fz_always entered as state < 3. makes state = 1
  177. * if (fz_throw called within fz_always)
  178. * fz_throw makes state = 3;
  179. * fz_always NOT entered as state >= 3
  180. * catch region entered with state = 3. OK.
  181. * else
  182. * catch region entered with state = 1.
  183. */
  184. FZ_NORETURN static void throw(fz_context *ctx, int code)
  185. {
  186. if (ctx->error.top > ctx->error.stack_base)
  187. {
  188. ctx->error.top->state += 2;
  189. if (ctx->error.top->code != FZ_ERROR_NONE)
  190. fz_warn(ctx, "clobbering previous error code and message (throw in always block?)");
  191. ctx->error.top->code = code;
  192. fz_longjmp(ctx->error.top->buffer, 1);
  193. }
  194. else
  195. {
  196. fz_flush_warnings(ctx);
  197. if (ctx->error.print)
  198. ctx->error.print(ctx->error.print_user, "aborting process from uncaught error!");
  199. exit(EXIT_FAILURE);
  200. }
  201. }
  202. fz_jmp_buf *fz_push_try(fz_context *ctx)
  203. {
  204. /* If we would overflow the exception stack, throw an exception instead
  205. * of entering the try block. We assume that we always have room for
  206. * 1 extra level on the stack here - i.e. we throw the error on us
  207. * starting to use the last level. */
  208. if (ctx->error.top + 2 >= ctx->error.stack_base + nelem(ctx->error.stack))
  209. {
  210. fz_strlcpy(ctx->error.message, "exception stack overflow!", sizeof ctx->error.message);
  211. fz_flush_warnings(ctx);
  212. if (ctx->error.print)
  213. ctx->error.print(ctx->error.print_user, ctx->error.message);
  214. /* We need to arrive in the always/catch block as if throw had taken place. */
  215. ctx->error.top++;
  216. ctx->error.top->state = 2;
  217. ctx->error.top->code = FZ_ERROR_LIMIT;
  218. }
  219. else
  220. {
  221. ctx->error.top++;
  222. ctx->error.top->state = 0;
  223. ctx->error.top->code = FZ_ERROR_NONE;
  224. }
  225. return &ctx->error.top->buffer;
  226. }
  227. int fz_do_try(fz_context *ctx)
  228. {
  229. #ifdef __COVERITY__
  230. return 1;
  231. #else
  232. return ctx->error.top->state == 0;
  233. #endif
  234. }
  235. int fz_do_always(fz_context *ctx)
  236. {
  237. #ifdef __COVERITY__
  238. return 1;
  239. #else
  240. if (ctx->error.top->state < 3)
  241. {
  242. ctx->error.top->state++;
  243. return 1;
  244. }
  245. return 0;
  246. #endif
  247. }
  248. int (fz_do_catch)(fz_context *ctx)
  249. {
  250. ctx->error.errcode = ctx->error.top->code;
  251. return (ctx->error.top--)->state > 1;
  252. }
  253. int fz_caught(fz_context *ctx)
  254. {
  255. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  256. return ctx->error.errcode;
  257. }
  258. int fz_caught_errno(fz_context *ctx)
  259. {
  260. assert(ctx && ctx->error.errcode == FZ_ERROR_SYSTEM);
  261. return ctx->error.errnum;
  262. }
  263. const char *fz_caught_message(fz_context *ctx)
  264. {
  265. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  266. return ctx->error.message;
  267. }
  268. void (fz_log_error_printf)(fz_context *ctx, const char *fmt, ...)
  269. {
  270. va_list ap;
  271. va_start(ap, fmt);
  272. (fz_vlog_error_printf)(ctx, fmt, ap);
  273. va_end(ap);
  274. }
  275. void (fz_vlog_error_printf)(fz_context *ctx, const char *fmt, va_list ap)
  276. {
  277. char message[256];
  278. fz_flush_warnings(ctx);
  279. if (ctx->error.print)
  280. {
  281. fz_vsnprintf(message, sizeof message, fmt, ap);
  282. message[sizeof(message) - 1] = 0;
  283. ctx->error.print(ctx->error.print_user, message);
  284. }
  285. }
  286. void (fz_log_error)(fz_context *ctx, const char *str)
  287. {
  288. fz_flush_warnings(ctx);
  289. if (ctx->error.print)
  290. ctx->error.print(ctx->error.print_user, str);
  291. }
  292. /* coverity[+kill] */
  293. FZ_NORETURN void (fz_vthrow)(fz_context *ctx, int code, const char *fmt, va_list ap)
  294. {
  295. if (ctx->error.errcode)
  296. {
  297. fz_flush_warnings(ctx);
  298. fz_warn(ctx, "UNHANDLED EXCEPTION!");
  299. fz_report_error(ctx);
  300. #ifdef CLUSTER
  301. abort();
  302. #endif
  303. }
  304. if (code == FZ_ERROR_SYSTEM)
  305. ctx->error.errnum = errno;
  306. else
  307. ctx->error.errnum = 0;
  308. fz_vsnprintf(ctx->error.message, sizeof ctx->error.message, fmt, ap);
  309. ctx->error.message[sizeof(ctx->error.message) - 1] = 0;
  310. throw(ctx, code);
  311. }
  312. /* coverity[+kill] */
  313. FZ_NORETURN void (fz_throw)(fz_context *ctx, int code, const char *fmt, ...)
  314. {
  315. va_list ap;
  316. va_start(ap, fmt);
  317. fz_vthrow(ctx, code, fmt, ap);
  318. va_end(ap);
  319. }
  320. /* coverity[+kill] */
  321. FZ_NORETURN void (fz_rethrow)(fz_context *ctx)
  322. {
  323. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  324. throw(ctx, ctx->error.errcode);
  325. }
  326. void (fz_morph_error)(fz_context *ctx, int fromerr, int toerr)
  327. {
  328. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  329. if (ctx->error.errcode == fromerr)
  330. ctx->error.errcode = toerr;
  331. }
  332. void (fz_rethrow_if)(fz_context *ctx, int err)
  333. {
  334. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  335. if (ctx->error.errcode == err)
  336. fz_rethrow(ctx);
  337. }
  338. void (fz_rethrow_unless)(fz_context *ctx, int err)
  339. {
  340. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  341. if (ctx->error.errcode != err)
  342. fz_rethrow(ctx);
  343. }
  344. static const char *
  345. fz_error_type_name(enum fz_error_type exc)
  346. {
  347. switch (exc)
  348. {
  349. case FZ_ERROR_NONE: return "none";
  350. case FZ_ERROR_GENERIC: return "generic";
  351. case FZ_ERROR_SYSTEM: return "system";
  352. case FZ_ERROR_LIBRARY: return "library";
  353. case FZ_ERROR_UNSUPPORTED: return "unsupported";
  354. case FZ_ERROR_ARGUMENT: return "argument";
  355. case FZ_ERROR_LIMIT: return "limit";
  356. case FZ_ERROR_FORMAT: return "format";
  357. case FZ_ERROR_SYNTAX: return "syntax";
  358. case FZ_ERROR_TRYLATER: return "trylater";
  359. case FZ_ERROR_ABORT: return "abort";
  360. case FZ_ERROR_REPAIRED: return "repaired";
  361. }
  362. return "invalid error type";
  363. }
  364. #if FZ_VERBOSE_EXCEPTIONS
  365. int fz_do_catchFL(fz_context *ctx, const char *file, int line)
  366. {
  367. int rc = (fz_do_catch)(ctx);
  368. if (rc)
  369. (fz_log_error_printf)(ctx, "%s:%d: Catching", file, line);
  370. return rc;
  371. }
  372. void fz_log_error_printfFL(fz_context *ctx, const char *file, int line, const char *fmt, ...)
  373. {
  374. va_list ap;
  375. va_start(ap, fmt);
  376. fz_vlog_error_printfFL(ctx, file, line, fmt, ap);
  377. va_end(ap);
  378. }
  379. void fz_vlog_error_printfFL(fz_context *ctx, const char *file, int line, const char *fmt, va_list ap)
  380. {
  381. char message[256];
  382. fz_flush_warnings(ctx);
  383. if (ctx->error.print)
  384. {
  385. fz_vsnprintf(message, sizeof message, fmt, ap);
  386. message[sizeof(message) - 1] = 0;
  387. fz_log_errorFL(ctx, file, line, message);
  388. }
  389. }
  390. void fz_log_errorFL(fz_context *ctx, const char *file, int line, const char *str)
  391. {
  392. char message[256];
  393. fz_flush_warnings(ctx);
  394. if (ctx->error.print)
  395. {
  396. fz_snprintf(message, sizeof message, "%s:%d '%s'", file, line, str);
  397. message[sizeof(message) - 1] = 0;
  398. ctx->error.print(ctx->error.print_user, message);
  399. }
  400. }
  401. /* coverity[+kill] */
  402. FZ_NORETURN void fz_vthrowFL(fz_context *ctx, const char *file, int line, int code, const char *fmt, va_list ap)
  403. {
  404. if (ctx->error.errcode)
  405. {
  406. fz_flush_warnings(ctx);
  407. fz_warn(ctx, "UNHANDLED EXCEPTION!");
  408. fz_report_error(ctx);
  409. #ifdef CLUSTER
  410. abort();
  411. #endif
  412. }
  413. fz_vsnprintf(ctx->error.message, sizeof ctx->error.message, fmt, ap);
  414. ctx->error.message[sizeof(ctx->error.message) - 1] = 0;
  415. (fz_log_error_printf)(ctx, "%s:%d: Throwing %s '%s'", file, line, fz_error_type_name(code), ctx->error.message);
  416. throw(ctx, code);
  417. }
  418. /* coverity[+kill] */
  419. FZ_NORETURN void fz_throwFL(fz_context *ctx, const char *file, int line, int code, const char *fmt, ...)
  420. {
  421. va_list ap;
  422. va_start(ap, fmt);
  423. fz_vthrowFL(ctx, file, line, code, fmt, ap);
  424. va_end(ap);
  425. }
  426. /* coverity[+kill] */
  427. FZ_NORETURN void fz_rethrowFL(fz_context *ctx, const char *file, int line)
  428. {
  429. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  430. (fz_log_error_printf)(ctx, "%s:%d: Rethrowing", file, line);
  431. throw(ctx, ctx->error.errcode);
  432. }
  433. void fz_morph_errorFL(fz_context *ctx, const char *file, int line, int fromerr, int toerr)
  434. {
  435. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  436. if (ctx->error.errcode == fromerr)
  437. {
  438. (fz_log_error_printf)(ctx, "%s:%d: Morphing %s->%s", file, line, fz_error_type_name(fromerr), fz_error_type_name(toerr));
  439. ctx->error.errcode = toerr;
  440. }
  441. }
  442. void fz_rethrow_unlessFL(fz_context *ctx, const char *file, int line, int err)
  443. {
  444. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  445. if (ctx->error.errcode != err)
  446. {
  447. (fz_log_error_printf)(ctx, "%s:%d: Rethrowing", file, line);
  448. (fz_rethrow)(ctx);
  449. }
  450. }
  451. void fz_rethrow_ifFL(fz_context *ctx, const char *file, int line, int err)
  452. {
  453. assert(ctx && ctx->error.errcode >= FZ_ERROR_NONE);
  454. if (ctx->error.errcode == err)
  455. {
  456. (fz_log_error_printf)(ctx, "%s:%d: Rethrowing", file, line);
  457. (fz_rethrow)(ctx);
  458. }
  459. }
  460. #endif
  461. void fz_start_throw_on_repair(fz_context *ctx)
  462. {
  463. fz_lock(ctx, FZ_LOCK_ALLOC);
  464. ctx->throw_on_repair++;
  465. fz_unlock(ctx, FZ_LOCK_ALLOC);
  466. }
  467. void fz_end_throw_on_repair(fz_context *ctx)
  468. {
  469. fz_lock(ctx, FZ_LOCK_ALLOC);
  470. ctx->throw_on_repair--;
  471. fz_unlock(ctx, FZ_LOCK_ALLOC);
  472. }
  473. void fz_report_error(fz_context *ctx)
  474. {
  475. #ifdef CLUSTER
  476. if (ctx->error.errcode == FZ_ERROR_TRYLATER || ctx->error.errcode == FZ_ERROR_ABORT)
  477. {
  478. fprintf(stderr, "REPORTED ERROR THAT IS TRYLATER OR ABORT\n");
  479. abort();
  480. }
  481. #endif
  482. /* TODO: send errcode to fz_log_error instead of formatting it here */
  483. fz_log_error_printf(ctx, "%s error: %s", fz_error_type_name(ctx->error.errcode), ctx->error.message);
  484. ctx->error.errcode = FZ_ERROR_NONE;
  485. }
  486. void fz_ignore_error(fz_context *ctx)
  487. {
  488. #ifdef CLUSTER
  489. if (ctx->error.errcode != FZ_ERROR_TRYLATER && ctx->error.errcode != FZ_ERROR_ABORT)
  490. {
  491. fprintf(stderr, "IGNORED ERROR THAT IS NOT TRYLATER OR ABORT\n");
  492. abort();
  493. }
  494. #endif
  495. ctx->error.errcode = FZ_ERROR_NONE;
  496. }
  497. /* Convert an error into another runtime exception. */
  498. const char *fz_convert_error(fz_context *ctx, int *code)
  499. {
  500. if (code)
  501. *code = ctx->error.errcode;
  502. ctx->error.errcode = FZ_ERROR_NONE;
  503. return ctx->error.message;
  504. }