error_delegate_util.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sql/error_delegate_util.h"
  5. #include <ostream> // Needed to compile NOTREACHED() with operator <<.
  6. #include <string>
  7. #include "base/files/file_path.h"
  8. #include "base/notreached.h"
  9. #include "third_party/sqlite/sqlite3.h"
  10. namespace sql {
  11. bool IsErrorCatastrophic(int sqlite_error_code) {
  12. // SQLite result codes are documented at https://www.sqlite.org/rescode.html
  13. int primary_error_code = sqlite_error_code & 0xff;
  14. // Within each group, error codes are sorted by their numerical values. This
  15. // matches the order used by the SQLite documentation describing them.
  16. switch (primary_error_code) {
  17. // Group of error codes that should never be returned by SQLite.
  18. //
  19. // If we do get these, our database schema / query pattern / data managed to
  20. // trigger a bug in SQLite. In development, we DCHECK to flag this SQLite
  21. // bug. In production, we [[fallback]] to corruption handling, because the
  22. // bug may be persistent, and corruption recovery will get the user unstuck.
  23. case SQLITE_INTERNAL: // Bug in SQLite.
  24. case SQLITE_EMPTY: // Marked for SQLite internal use.
  25. case SQLITE_FORMAT: // Not currently used, according to SQLite docs.
  26. case SQLITE_NOTICE: // Only used as an argument to sqlite3_log().
  27. case SQLITE_WARNING: // Only used as an argument to sqlite3_log().
  28. NOTREACHED() << "SQLite returned result code marked for internal use: "
  29. << sqlite_error_code;
  30. [[fallthrough]];
  31. // Group of error codes that may only be returned by SQLite (given Chrome's
  32. // usage patterns) if a database is corrupted. DCHECK would not be
  33. // appropriate, since these can occur in production. Silently [[fallback]]
  34. // to corruption handling.
  35. case SQLITE_ERROR:
  36. // Generic/fallback error code.
  37. //
  38. // This error code is thrown when Chrome issues an invalid SQL statement.
  39. // For instance, the SQL statement may reference a table or column which
  40. // doesn't exist.
  41. //
  42. // This can happen in two scenarios:
  43. // 1. There's a programmer error, and we have an outdated SQL statement
  44. // somewhere in the code.
  45. // 2. The user's database got corrupted and the expected table or column
  46. // names are no longer there.
  47. //
  48. // TODO(https://crbug.com/1321483): In practice, we're logging a
  49. // surprisingly lot of errors of this type, and the counts aren't going
  50. // down, so there must be some instances of Case #1. Log and fix those
  51. // cases, then turn this back to [[fallthrough]].
  52. return false;
  53. case SQLITE_PERM:
  54. // Failed to get the requested access mode for a newly created database.
  55. // The database was just created, so error recovery will not cause data
  56. // loss. Error recovery steps, such as re-creating database files, may
  57. // fix the permission problems.
  58. [[fallthrough]];
  59. case SQLITE_CORRUPT:
  60. // Some form of database corruption was detected. The sql::Recovery code
  61. // may be able to recover some of the data.
  62. [[fallthrough]];
  63. case SQLITE_CANTOPEN:
  64. // Failed to open the database, for a variety of reasons. All the reasons
  65. // come down to some form of corruption. Here are some known reasons:
  66. // * One of the file names (database, journal, WAL, etc.) points to a
  67. // directory, not a file. This indicates filesystem corruption. Most
  68. // likely, some app messed with the user's Chrome file. It's also
  69. // possible that the inode was corrupted and the is_dir bit flipped.
  70. // * One of the file names is a symlink, and SQLite was instructed not to
  71. // follow symlinks. This should not occur in Chrome, we let SQLite use
  72. // its default symlink handling.
  73. // * The WAL file has a format version that SQLite can't understand. This
  74. // should not occur in Chrome, as we don't use WAL yet.
  75. [[fallthrough]];
  76. case SQLITE_MISMATCH:
  77. // SQLite was forced to perform an operation that involves incompatible
  78. // data types. An example is attempting to store a non-integer value in a
  79. // ROWID primary key.
  80. //
  81. // In production, database corruption can lead to this. For example, it's
  82. // possible that a schema is corrupted in such a way that the ROWID
  83. // primary key column's name is swapped with another column's name.
  84. [[fallthrough]];
  85. case SQLITE_NOLFS:
  86. // The database failed to grow past the filesystem size limit. This is
  87. // unlikely to happen in Chrome, but it is theoretically possible.
  88. [[fallthrough]];
  89. case SQLITE_NOTADB:
  90. // The database header is corrupted. The sql::Recovery code will not be
  91. // able to recovery any data, as SQLite will refuse to open the database.
  92. return true;
  93. // Group of result codes that are not error codes. These should never make
  94. // it to error handling code. In development, we DCHECK to flag this Chrome
  95. // bug. In production, we hope this is a transient error, such as a race
  96. // condition.
  97. case SQLITE_OK: // Most used success code.
  98. case SQLITE_ROW: // The statement produced a row of output.
  99. case SQLITE_DONE: // A step has completed in a multi-step operation.
  100. NOTREACHED() << "Called with non-error result code " << sqlite_error_code;
  101. [[fallthrough]];
  102. // Group of error codes that should not be returned by SQLite given Chrome's
  103. // usage patterns, even if the database gets corrupted. In development, we
  104. // DCHECK to flag this Chrome bug. In production, we hope the errors have
  105. // transient causes, such as race conditions.
  106. case SQLITE_LOCKED:
  107. // Conflict between two concurrently executing statements in the same
  108. // database connection.
  109. //
  110. // In theory, SQLITE_LOCKED could also signal a conflict between different
  111. // connections (in the same process) sharing a page cache, but Chrome only
  112. // uses private page caches.
  113. NOTREACHED() << "Conflict between concurrently executing SQL statements";
  114. [[fallthrough]];
  115. case SQLITE_NOMEM:
  116. // Out of memory. This is most likely a transient error.
  117. //
  118. // There's a small chance that the error is caused by trying to exchange
  119. // too much data with SQLite. Most such errors result in SQLITE_TOOBIG.
  120. NOTREACHED() << "SQLite reported out-of-memory: " << sqlite_error_code;
  121. [[fallthrough]];
  122. case SQLITE_INTERRUPT:
  123. // Chrome features don't use sqlite3_interrupt().
  124. NOTREACHED() << "SQLite returned INTERRUPT code: " << sqlite_error_code;
  125. [[fallthrough]];
  126. case SQLITE_NOTFOUND:
  127. // Unknown opcode in sqlite3_file_control(). Chrome's features only use a
  128. // few built-in opcodes.
  129. NOTREACHED() << "SQLite returned NOTFOUND code: " << sqlite_error_code;
  130. [[fallthrough]];
  131. case SQLITE_MISUSE:
  132. // SQLite API misuse, such as trying to use a prepared statement after it
  133. // was finalized. In development, we DCHECK to flag this Chrome bug. In
  134. // production, we hope this is a race condition, and therefore transient.
  135. NOTREACHED() << "SQLite returned MISUSE code: " << sqlite_error_code;
  136. [[fallthrough]];
  137. case SQLITE_AUTH:
  138. // Chrome features don't install an authorizer callback. Only WebSQL does.
  139. NOTREACHED() << "SQLite returned AUTH code: " << sqlite_error_code;
  140. [[fallthrough]];
  141. case SQLITE_RANGE:
  142. // Chrome uses DCHECKs to ensure the validity of column indexes passed to
  143. // sqlite3_bind() and sqlite3_column().
  144. NOTREACHED() << "SQLite returned RANGE code: " << sqlite_error_code;
  145. [[fallthrough]];
  146. // Group of error codes that should may be returned by SQLite given Chrome's
  147. // usage patterns, even without database corruption. In development, we
  148. // DCHECK to flag this Chrome bug. In production, we hope the errors have
  149. // transient causes, such as race conditions.
  150. case SQLITE_ABORT:
  151. // SQLITE_ABORT may be returned when a ROLLBACK statement is executed
  152. // concurrently with a pending read or write, and Chrome features are
  153. // allowed to execute concurrent statements in the same transaction, under
  154. // some conditions.
  155. //
  156. // It may be worth noting that Chrome features don't use callback routines
  157. // that may abort SQL statements, such as passing a callback to
  158. // sqlite3_exec().
  159. [[fallthrough]];
  160. case SQLITE_BUSY:
  161. // Failed to grab a lock on the database. Another database connection
  162. // (most likely in another process) is holding the database lock. This
  163. // should not be a problem for exclusive databases, which are strongly
  164. // recommended for Chrome features.
  165. [[fallthrough]];
  166. case SQLITE_READONLY:
  167. // SQLite either failed to write to the database file or its associated
  168. // files (journal, WAL, etc.), or considers it unsafe to do so.
  169. //
  170. // Most error codes (SQLITE_READONLY_DIRECTORY, SQLITE_READONLY_RECOVERY,
  171. // SQLITE_READONLY_ROLLBACK, SQLITE_READONLY_CANTLOCK) mean that SQLite
  172. // failed to write to some file, or to create a file (which entails
  173. // writing to the directory containing the database).
  174. //
  175. // SQLITE_READONLY_CANTLOCK should never happen in Chrome, because we will
  176. // only allow enabling WAL on databases that use exclusive locking.
  177. //
  178. // Unlike all other codes, SQLITE_READONLY_DBMOVED signals that a file was
  179. // deleted or renamed. It is returned when SQLite realizes that the
  180. // database file was moved or unlinked from the filesystem after it was
  181. // opened, so the associated files (journal, WAL, etc.) would not be found
  182. // by another SQLite instance in the event of a crash. This was observed
  183. // on the iOS try bots.
  184. [[fallthrough]];
  185. case SQLITE_IOERR:
  186. // Catch-all for many errors reported by the VFS. Some of the errors
  187. // indicate media failure (SQLITE_IOERR_READ), while others indicate
  188. // transient problems (SQLITE_IOERR_LOCK). In the future, we may invest in
  189. // distinguishing between them. For now, since all the codes are bundled
  190. // up, we must assume that the error is transient.
  191. [[fallthrough]];
  192. case SQLITE_FULL:
  193. // The disk is full. This is definitely a transient error, and does not
  194. // indicate any database corruption. While it's true that the user will be
  195. // stuck in this state until some action is taken, we're unlikely to help
  196. // the user if we run our recovery code or delete our databases.
  197. [[fallthrough]];
  198. case SQLITE_PROTOCOL:
  199. // Gave up while attempting to grab a lock on a WAL database at the
  200. // beginning of a transaction. In theory, this should not be a problem in
  201. // Chrome, because we'll only allow enabling WAL on databases with
  202. // exclusive locking. However, other software on the user's system may
  203. // lock our databases in a way that triggers this error.
  204. [[fallthrough]];
  205. case SQLITE_SCHEMA:
  206. // The database schema was changed between the time when a prepared
  207. // statement was compiled, and when it was executing.
  208. //
  209. // This can happen in production. Databases that don't use exclusive
  210. // locking (recommended but not yet required for Chrome features) may be
  211. // changed from another process via legitimate use of SQLite APIs.
  212. // Databases that do use exclusive locks may still be mutated on-disk, on
  213. // operating systems where exclusive locks are only enforced via advisory
  214. // locking.
  215. //
  216. // When we mandate exclusive locks for all features in Chrome, we may
  217. // classify this error as database corruption, because it is an indicator
  218. // that another process is interfering with Chrome's schemas.
  219. [[fallthrough]];
  220. case SQLITE_TOOBIG:
  221. // SQLite encountered a string or blob whose length exceeds
  222. // SQLITE_MAX_LENGTH, or it was asked to execute a SQL statement whose
  223. // length exceeds SQLITE_MAX_SQL_LENGTH or SQLITE_LIMIT_SQL_LENGTH.
  224. //
  225. // A corrupted database could cause this in the following ways:
  226. // * SQLite could encounter an overly large string or blob because its
  227. // size field got corrupted.
  228. // * SQLite could attempt to execute an overly large SQL statement while
  229. // operating on a corrupted schema. (Some of SQLite's DDL statements
  230. // involve executing SQL that includes schema content.)
  231. //
  232. // However, this could also occur due to a Chrome bug where we ask SQLite
  233. // to bind an overly large string or blob. So, we currently don't classify
  234. // this as definitely induced by corruption.
  235. [[fallthrough]];
  236. case SQLITE_CONSTRAINT:
  237. // This can happen in production, when executing SQL statements with the
  238. // semantics of "create a record if it doesn't exist, otherwise do
  239. // nothing".
  240. return false;
  241. }
  242. NOTREACHED() << "SQLite returned unknown result code: " << sqlite_error_code;
  243. return false;
  244. }
  245. std::string GetCorruptFileDiagnosticsInfo(
  246. const base::FilePath& corrupted_file_path) {
  247. std::string corrupted_file_info("Corrupted file: ");
  248. corrupted_file_info +=
  249. corrupted_file_path.DirName().BaseName().AsUTF8Unsafe() + "/" +
  250. corrupted_file_path.BaseName().AsUTF8Unsafe() + "\n";
  251. return corrupted_file_info;
  252. }
  253. } // namespace sql