]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Round one of an audit for SQLITE_ENABLE_API_ARMOR for functions exposed by JNI and...
authorstephan <stephan@noemail.net>
Fri, 13 Oct 2023 12:48:35 +0000 (12:48 +0000)
committerstephan <stephan@noemail.net>
Fri, 13 Oct 2023 12:48:35 +0000 (12:48 +0000)
FossilOrigin-Name: 8c25c4b18ad07861bf0e47f99f3db04b569b9b859ad0690602f748ddf3576939

ext/jni/src/c/sqlite3-jni.c
manifest
manifest.uuid
src/loadext.c
src/main.c
src/notify.c
src/vdbeapi.c

index 7afc9a0f0fcf792a2563a777eb9f424e62aa5d2e..1465c9e6513439e02d1befda7addb832ae380bdb 100644 (file)
@@ -972,6 +972,7 @@ static jstring s3jni__utf8_to_jstring(JNIEnv * const env,
        hypothetically do this for any strings where n<4 and z is
        NUL-terminated and none of z[0..3] are NUL bytes. */
     rv = (*env)->NewStringUTF(env, "");
+    s3jni_oom_check( rv );
   }else if( z ){
     jbyteArray jba;
     if( n<0 ) n = sqlite3Strlen30(z);
@@ -985,8 +986,8 @@ static jstring s3jni__utf8_to_jstring(JNIEnv * const env,
       }
       S3JniUnrefLocal(jba);
     }
+    s3jni_oom_check( rv );
   }
-  s3jni_oom_check( rv );
   return rv;
 }
 #define s3jni_utf8_to_jstring(CStr,n) s3jni__utf8_to_jstring(env, CStr, n)
@@ -1468,12 +1469,14 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph,
 #define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
 #define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
 /*
-** S3JniLongPtr_T(X,Y) expects X to be an unqualified sqlite3
-** struct type name and Y to be a native pointer to such an object in
-** the form of a jlong value. The jlong is simply cast to (X*). This
+** S3JniLongPtr_T(X,Y) expects X to be an unqualified sqlite3 struct
+** type name and Y to be a native pointer to such an object in the
+** form of a jlong value. The jlong is simply cast to (X*). This
 ** approach is, as of 2023-09-27, supplanting the former approach. We
 ** now do the native pointer extraction in the Java side, rather than
-** the C side, because it's reportedly significantly faster.
+** the C side, because it's reportedly significantly faster. The
+** intptr_t part here is necessary for compatibility with (at least)
+** ARM32.
 */
 #define S3JniLongPtr_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr))
 #define S3JniLongPtr_sqlite3(JLongAsPtr) S3JniLongPtr_T(sqlite3,JLongAsPtr)
@@ -2616,6 +2619,10 @@ S3JniApi(sqlite3_cancel_auto_extension(),jboolean,1cancel_1auto_1extension)(
   S3JniAutoExtension * ax;
   jboolean rc = JNI_FALSE;
   int i;
+
+  if( !jAutoExt ){
+    return rc;
+  }
   S3JniAutoExt_mutex_enter;
   /* This algo corresponds to the one in the core. */
   for( i = SJG.autoExt.nExt-1; i >= 0; --i ){
@@ -2778,8 +2785,8 @@ S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)(
   JniArgsEnvClass, jobject jpStmt, jint ndx
 ){
   sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt);
-  const unsigned char * const p = sqlite3_column_text(stmt, (int)ndx);
-  const int n = sqlite3_column_bytes(stmt, (int)ndx);
+  const unsigned char * const p = stmt ? sqlite3_column_text(stmt, (int)ndx) : 0;
+  const int n = p ? sqlite3_column_bytes(stmt, (int)ndx) : 0;
   return p ? s3jni_new_jbyteArray(p, n) : NULL;
 }
 
@@ -2789,8 +2796,8 @@ S3JniApi(sqlite3_column_text(),jstring,1column_1text)(
   JniArgsEnvClass, jobject jpStmt, jint ndx
 ){
   sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt);
-  const unsigned char * const p = sqlite3_column_text(stmt, (int)ndx);
-  const int n = sqlite3_column_bytes(stmt, (int)ndx);
+  const unsigned char * const p = stmt ? sqlite3_column_text(stmt, (int)ndx) : 0;
+  const int n = p ? sqlite3_column_bytes(stmt, (int)ndx) : 0;
   return p ? s3jni_utf8_to_jstring( (const char *)p, n) : 0;
 }
 #endif
@@ -2799,8 +2806,8 @@ S3JniApi(sqlite3_column_text16(),jstring,1column_1text16)(
   JniArgsEnvClass, jobject jpStmt, jint ndx
 ){
   sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jpStmt);
-  const void * const p = sqlite3_column_text16(stmt, (int)ndx);
-  const int n = sqlite3_column_bytes16(stmt, (int)ndx);
+  const void * const p = stmt ? sqlite3_column_text16(stmt, (int)ndx) : 0;
+  const int n = p ? sqlite3_column_bytes16(stmt, (int)ndx) : 0;
   return s3jni_text16_to_jstring(env, p, n);
 }
 
@@ -2808,7 +2815,8 @@ S3JniApi(sqlite3_column_value(),jobject,1column_1value)(
   JniArgsEnvClass, jobject jpStmt, jint ndx
 ){
   sqlite3_value * const sv =
-    sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
+    sqlite3_column_value(PtrGet_sqlite3_stmt(jpStmt), (int)ndx)
+    /* reminder: returns an SQL NULL if jpStmt==NULL */;
   return new_java_sqlite3_value(env, sv);
 }
 
@@ -2919,6 +2927,18 @@ S3JniApi(sqlite3_compileoption_get(),jstring,1compileoption_1get)(
   return rv;
 }
 
+S3JniApi(sqlite3_compileoption_used(),jboolean,1compileoption_1used)(
+  JniArgsEnvClass, jstring name
+){
+  const char *zUtf8 = s3jni_jstring_to_mutf8(name)
+    /* We know these to be ASCII, so MUTF-8 is fine (and
+       hypothetically faster to convert). */;
+  const jboolean rc =
+    0==sqlite3_compileoption_used(zUtf8) ? JNI_FALSE : JNI_TRUE;
+  s3jni_mutf8_release(name, zUtf8);
+  return rc;
+}
+
 S3JniApi(sqlite3_complete(),int,1complete)(
   JniArgsEnvClass, jbyteArray jSql
 ){
@@ -2935,18 +2955,6 @@ S3JniApi(sqlite3_complete(),int,1complete)(
   return rc;
 }
 
-S3JniApi(sqlite3_compileoption_used(),jboolean,1compileoption_1used)(
-  JniArgsEnvClass, jstring name
-){
-  const char *zUtf8 = s3jni_jstring_to_mutf8(name)
-    /* We know these to be ASCII, so MUTF-8 is fine (and
-       hypothetically faster to convert). */;
-  const jboolean rc =
-    0==sqlite3_compileoption_used(zUtf8) ? JNI_FALSE : JNI_TRUE;
-  s3jni_mutf8_release(name, zUtf8);
-  return rc;
-}
-
 S3JniApi(sqlite3_config() /*for a small subset of options.*/,
          jint,1config__I)(JniArgsEnvClass, jint n){
   switch( n ){
@@ -3151,6 +3159,9 @@ S3JniApi(sqlite3_create_collation() sqlite3_create_collation_v2(),
   int rc;
   S3JniDb * ps;
 
+  if( !jDb || !name || !encodingTypeIsValid(eTextRep) ){
+    return (jint)SQLITE_MISUSE;
+  }
   S3JniDb_mutex_enter;
   ps = S3JniDb_from_java(jDb);
   jclass const klazz = (*env)->GetObjectClass(env, oCollation);
@@ -3574,6 +3585,7 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnv **jc,
                           S3JniDb ** ps){
   int rc = 0;
   jobject jDb = 0;
+
   *jc = S3JniEnv_get();
   if( !*jc ){
     rc = SQLITE_NOMEM;
@@ -3650,6 +3662,8 @@ S3JniApi(sqlite3_open(),jint,1open)(
   S3JniDb * ps = 0;
   S3JniEnv * jc = 0;
   int rc;
+
+  if( 0==jOut ) return SQLITE_MISUSE;
   rc = s3jni_open_pre(env, &jc, strName, &zName, &ps);
   if( 0==rc ){
     rc = s3jni_open_post(env, jc, ps, &pOut, jOut,
@@ -3662,14 +3676,17 @@ S3JniApi(sqlite3_open(),jint,1open)(
 
 S3JniApi(sqlite3_open_v2(),jint,1open_1v2)(
   JniArgsEnvClass, jstring strName,
-                      jobject jOut, jint flags, jstring strVfs
+  jobject jOut, jint flags, jstring strVfs
 ){
   sqlite3 * pOut = 0;
   char *zName = 0;
   S3JniDb * ps = 0;
   S3JniEnv * jc = 0;
   char *zVfs = 0;
-  int rc = s3jni_open_pre(env, &jc, strName, &zName, &ps);
+  int rc;
+
+  if( 0==jOut ) return SQLITE_MISUSE;
+  rc = s3jni_open_pre(env, &jc, strName, &zName, &ps);
   if( 0==rc ){
     if( strVfs ){
       zVfs = s3jni_jstring_to_utf8( strVfs, 0);
@@ -4469,7 +4486,6 @@ static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
   jbyte * const pG = s3jni_jbyteArray_bytes(baG);
   jbyte * const pT = pG ? s3jni_jbyteArray_bytes(baT) : 0;
 
-  s3jni_oom_fatal(pT);
   /* Note that we're relying on the byte arrays having been
      NUL-terminated on the Java side. */
   rc = isLike
@@ -4509,12 +4525,8 @@ S3JniApi(sqlite3_sql(),jstring,1sql)(
 S3JniApi(sqlite3_step(),jint,1step)(
   JniArgsEnvClass,jobject jStmt
 ){
-  int rc = SQLITE_MISUSE;
   sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jStmt);
-  if( pStmt ){
-    rc = sqlite3_step(pStmt);
-  }
-  return rc;
+  return pStmt ? (jint)sqlite3_step(pStmt) : (jint)SQLITE_MISUSE;
 }
 
 S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)(
index 667e06fa718d267f09ff26d6ef95894d972df405..f9baa60087441223d88ba78b79b7fa6bd570f31e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Avoid\spotential\soverflow\sin\shex().\s[forum:/forumpost/7ac0c9c5ea|See\sforum\spost\s7ac0c9c5ea.]
-D 2023-10-13T01:39:47.068
+C Round\sone\sof\san\saudit\sfor\sSQLITE_ENABLE_API_ARMOR\sfor\sfunctions\sexposed\sby\sJNI\sand\sthose\sfunctions\smissing\sarmor,\sas\s[forum:5e3fc453a69b49ca|reported\sin\sseveral\sforum\sposts].
+D 2023-10-13T12:48:35.298
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -238,7 +238,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
 F ext/jni/GNUmakefile 6da240c9a11701f3ed569384cd15ef611e8b3c5e3897d265923b14bf0e1eb272
 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
-F ext/jni/src/c/sqlite3-jni.c bf432771fbc84da2b5f4037e0bcf20757548aac2fa782b272c4894a9c279964a
+F ext/jni/src/c/sqlite3-jni.c eabd48ced29954fb4f6173c4f350f7f1fce218ce19f48a75367cb560cf2da77e
 F ext/jni/src/c/sqlite3-jni.h be1fdff7ab3a2bb357197271c8ac5d2bf6ff59380c106dde3a13be88724bad22
 F ext/jni/src/org/sqlite/jni/AbstractCollationCallback.java 95e88ba04f4aac51ffec65693e878e234088b2f21b387f4e4285c8b72b33e436
 F ext/jni/src/org/sqlite/jni/AggregateFunction.java 7312486bc65fecdb91753c0a4515799194e031f45edbe16a6373cea18f404dc4
@@ -676,8 +676,8 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
 F src/json.c 799430345d16fed21713416318e6ca616f1264224f708555f387bfa2ab2496c7
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
-F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
-F src/main.c 618aeb399e993cf561864f4b0cf6a331ee4f355cf663635f8d9da3193a46aa40
+F src/loadext.c 7d56c6f28aaf9b42e2772289e0d0a12a77b57c2baed021dbfd1fcafec69c156a
+F src/main.c 7a91b372dd1bada07c5b5e36082dc0d695161c3807efe2386f563a5b32446ae6
 F src/malloc.c f016922435dc7d1f1f5083a03338a3e91f8c67ce2c5bdcfa4cdef62e612f5fcc
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -692,7 +692,7 @@ F src/mutex.h a7b2293c48db5f27007c3bdb21d438873637d12658f5a0bf8ad025bb96803c4a
 F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
 F src/mutex_unix.c bd52ec50e44a41fe1e3deb5a6e3fe98edb6f2059da3e46d196363d0fa3192cda
 F src/mutex_w32.c 38b56d0bc8d54c17c20cbaaad3719b0c36b92fd07a7e34360d0c6a18d5589912
-F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6
+F src/notify.c 57c2d1a2805d6dee32acd5d250d928ab94e02d76369ae057dee7d445fd64e878
 F src/os.c 509452169d5ea739723e213b8e2481cf0e587f0e88579a912d200db5269f5f6d
 F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
 F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
@@ -787,7 +787,7 @@ F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
 F src/vdbe.c cd112eb00d20fc5cc44f631d0e713838602637328b0f127c2f3c2aa8cea3cc91
 F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
 F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
-F src/vdbeapi.c 4184402246172220418c0ef49ff4cf1a19ced9a4ac6c843c2f0773fb5c543f37
+F src/vdbeapi.c be7d88a05df51cb3940304f74e4b0534817b51213b3406143a67eecd6f82fe21
 F src/vdbeaux.c 5b415e09b5b9d5be6c0f4fcbf18ea9d7d16f6a29ced2f14a3b2041020f63e9c1
 F src/vdbeblob.c 4cf5aa130e96e3b52ba3fb54b7f9606c942ab988dbb32cb19cff4db24e06aeec
 F src/vdbemem.c 317b9f48708139db6239ade40c7980b4bc8233168383690d588dad6d8437f722
@@ -2128,8 +2128,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 4a4eccb681741917c6771101d4e329f91eae9b035f4d345218e522bb55fff6da
-R b8db52c4af481f11a25564ae1b4169f0
-U larrybr
-Z e40ad0deba084d2d357f307fa10fdd72
+P 2e968114fd0e60eebcc088dec02684e10b06ac1ec42d6bedb5287362f5cbf032
+R 64d7e862f198f312cf375ff0e1b4824a
+T *branch * api-armor-audit
+T *sym-api-armor-audit *
+T -sym-trunk * Cancelled\sby\sbranch.
+U stephan
+Z fb0f8b82a9c86be7bcd5823447ca13df
 # Remove this line to create a well-formed Fossil manifest.
index 1d7dc6eb7c1d6fbaa574236c45efa935af63e39d..7b111488b34640bb35763ba8999b2ffe3a7d273c 100644 (file)
@@ -1 +1 @@
-2e968114fd0e60eebcc088dec02684e10b06ac1ec42d6bedb5287362f5cbf032
\ No newline at end of file
+8c25c4b18ad07861bf0e47f99f3db04b569b9b859ad0690602f748ddf3576939
\ No newline at end of file
index e792fa5a9833f715b3de702e93e78cd1a1183e74..cfa8ba4ca858de217e038adc4b1b879b03d440c7 100644 (file)
@@ -730,6 +730,9 @@ void sqlite3CloseExtensions(sqlite3 *db){
 ** default so as not to open security holes in older applications.
 */
 int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
   sqlite3_mutex_enter(db->mutex);
   if( onoff ){
     db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
@@ -751,7 +754,7 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
 */
 typedef struct sqlite3AutoExtList sqlite3AutoExtList;
 static SQLITE_WSD struct sqlite3AutoExtList {
-  u32 nExt;              /* Number of entries in aExt[] */          
+  u32 nExt;              /* Number of entries in aExt[] */
   void (**aExt)(void);   /* Pointers to the extension init functions */
 } sqlite3Autoext = { 0, 0 };
 
@@ -779,6 +782,9 @@ int sqlite3_auto_extension(
   void (*xInit)(void)
 ){
   int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( xInit==0 ) return SQLITE_MISUSE_BKPT;
+#endif
 #ifndef SQLITE_OMIT_AUTOINIT
   rc = sqlite3_initialize();
   if( rc ){
@@ -831,6 +837,9 @@ int sqlite3_cancel_auto_extension(
   int i;
   int n = 0;
   wsdAutoextInit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( xInit==0 ) return 0;
+#endif
   sqlite3_mutex_enter(mutex);
   for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
     if( wsdAutoext.aExt[i]==xInit ){
index a43afab1686ccef1c2d6f963a2de1549d624cddc..4ddf7e24d3ddfab52470fc32f93652482c7185ce 100644 (file)
@@ -954,6 +954,10 @@ int sqlite3_db_cacheflush(sqlite3 *db){
 int sqlite3_db_config(sqlite3 *db, int op, ...){
   va_list ap;
   int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
   sqlite3_mutex_enter(db->mutex);
   va_start(ap, op);
   switch( op ){
@@ -2365,6 +2369,12 @@ void *sqlite3_preupdate_hook(
   void *pArg                /* First callback argument */
 ){
   void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( db==0 || xCallback==0 ){
+    return;
+  }
+#endif
   sqlite3_mutex_enter(db->mutex);
   pRet = db->pPreUpdateArg;
   db->xPreUpdateCallback = xCallback;
index 4960ab76b1098557d78d9a1c32272528109a01fd..6a4cab8755017c3e7f95c314d3673f6252fcbe10 100644 (file)
@@ -152,6 +152,9 @@ int sqlite3_unlock_notify(
 ){
   int rc = SQLITE_OK;
 
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
   sqlite3_mutex_enter(db->mutex);
   enterMutex();
 
index 1213dbe6d12f8093a0d2ceb0363d6fad90198b15..f8e66df87a6c4613b2c947382c4f098226bac011 100644 (file)
@@ -2029,10 +2029,16 @@ static UnpackedRecord *vdbeUnpackRecord(
 ** a field of the row currently being updated or deleted.
 */
 int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
-  PreUpdate *p = db->pPreUpdate;
+  PreUpdate *p;
   Mem *pMem;
   int rc = SQLITE_OK;
 
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( db==0 || ppValue==0 ){
+    return SQLITE_MISUSE_BKPT;
+  }
+#endif
+  p = db->pPreUpdate;
   /* Test that this call is being made from within an SQLITE_DELETE or
   ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
   if( !p || p->op==SQLITE_INSERT ){
@@ -2093,7 +2099,12 @@ int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
 ** the number of columns in the row being updated, deleted or inserted.
 */
 int sqlite3_preupdate_count(sqlite3 *db){
-  PreUpdate *p = db->pPreUpdate;
+  PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+  p = db!=0 ? db->pPreUpdate : 0;
+#else
+  p = db->pPreUpdate;
+#endif
   return (p ? p->keyinfo.nKeyField : 0);
 }
 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -2111,7 +2122,12 @@ int sqlite3_preupdate_count(sqlite3 *db){
 ** or SET DEFAULT action is considered a trigger.
 */
 int sqlite3_preupdate_depth(sqlite3 *db){
-  PreUpdate *p = db->pPreUpdate;
+  PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+  p = db!=0 ? db->pPreUpdate : 0;
+#else
+  p = db->pPreUpdate;
+#endif
   return (p ? p->v->nFrame : 0);
 }
 #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -2122,7 +2138,12 @@ int sqlite3_preupdate_depth(sqlite3 *db){
 ** only.
 */
 int sqlite3_preupdate_blobwrite(sqlite3 *db){
-  PreUpdate *p = db->pPreUpdate;
+  PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+  p = db!=0 ? db->pPreUpdate : 0;
+#else
+  p = db->pPreUpdate;
+#endif
   return (p ? p->iBlobWrite : -1);
 }
 #endif
@@ -2133,10 +2154,16 @@ int sqlite3_preupdate_blobwrite(sqlite3 *db){
 ** a field of the row currently being updated or inserted.
 */
 int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
-  PreUpdate *p = db->pPreUpdate;
+  PreUpdate *p;
   int rc = SQLITE_OK;
   Mem *pMem;
 
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( db==0 || ppValue==0 ){
+    return SQLITE_MISUSE_BKPT;
+  }
+#endif
+  p = db->pPreUpdate;
   if( !p || p->op==SQLITE_DELETE ){
     rc = SQLITE_MISUSE_BKPT;
     goto preupdate_new_out;