Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package otpclient for openSUSE:Factory 
checked in at 2026-07-21 23:00:41
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/otpclient (Old)
 and      /work/SRC/openSUSE:Factory/.otpclient.new.24530 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "otpclient"

Tue Jul 21 23:00:41 2026 rev:52 rq:1366749 version:5.1.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/otpclient/otpclient.changes      2026-07-14 
13:57:01.701595758 +0200
+++ /work/SRC/openSUSE:Factory/.otpclient.new.24530/otpclient.changes   
2026-07-21 23:00:44.022398151 +0200
@@ -1,0 +2,17 @@
+Mon Jul 20 06:27:59 UTC 2026 - Paolo Stivanin <[email protected]>
+
+- Update to 5.1.5:
+  * FIX: a database stored on a filesystem without lock support
+    (the Flatpak document portal, and some NFS/SMB mounts) could
+    not be opened or created, failing with Failed to acquire
+    database lock: Function not implemented. Locking is now best-
+    effort, so the database opens normally on those filesystems,
+    while real locking is unchanged everywhere else (#466)
+  * FIX: the secure-memory pool reserved the whole RLIMIT_MEMLOCK
+    budget, so the GTK password entry could not lock its own buffer
+    and warned couldn't lock 16384 bytes of memory (gtk): Cannot
+    allocate memory, falling back to unlocked memory for the typed
+    password on every unlock. The pool now leaves headroom for it
+    (Debian #1141809)
+
+-------------------------------------------------------------------

Old:
----
  v5.1.4.tar.gz
  v5.1.4.tar.gz.asc

New:
----
  v5.1.5.tar.gz
  v5.1.5.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ otpclient.spec ++++++
--- /var/tmp/diff_new_pack.HKGgiS/_old  2026-07-21 23:00:45.642454026 +0200
+++ /var/tmp/diff_new_pack.HKGgiS/_new  2026-07-21 23:00:45.646454164 +0200
@@ -18,7 +18,7 @@
 
 %define uclname OTPClient
 Name:           otpclient
-Version:        5.1.4
+Version:        5.1.5
 Release:        0
 Summary:        Simple GTK+ client for managing TOTP and HOTP
 License:        GPL-3.0-or-later

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.HKGgiS/_old  2026-07-21 23:00:45.710456371 +0200
+++ /var/tmp/diff_new_pack.HKGgiS/_new  2026-07-21 23:00:45.718456647 +0200
@@ -1,5 +1,5 @@
-mtime: 1783677767
-commit: 04838f01d636678220ee57cb23fc179016d264a8d2db38d44d75884e0a1996f0
+mtime: 1784528910
+commit: c5dfc727873cc35fbd92e5d70d25aa51991e7f0c910ac0fade8ac2b3e21ef9a1
 url: https://src.opensuse.org/GNOME/otpclient
 revision: factory
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-07-20 08:28:30.000000000 +0200
@@ -0,0 +1,4 @@
+*.obscpio
+*.osc
+_build.*
+.pbuild


++++++ v5.1.4.tar.gz -> v5.1.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/CMakeLists.txt 
new/OTPClient-5.1.5/CMakeLists.txt
--- old/OTPClient-5.1.4/CMakeLists.txt  2026-07-10 11:41:32.000000000 +0200
+++ new/OTPClient-5.1.5/CMakeLists.txt  2026-07-16 17:45:17.000000000 +0200
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.25)
-project(OTPClient VERSION "5.1.4" LANGUAGES "C")
+project(OTPClient VERSION "5.1.5" LANGUAGES "C")
 include(GNUInstallDirs)
 include(CTest)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/OTPClient-5.1.4/data/com.github.paolostivanin.OTPClient.appdata.xml 
new/OTPClient-5.1.5/data/com.github.paolostivanin.OTPClient.appdata.xml
--- old/OTPClient-5.1.4/data/com.github.paolostivanin.OTPClient.appdata.xml     
2026-07-10 11:41:32.000000000 +0200
+++ new/OTPClient-5.1.5/data/com.github.paolostivanin.OTPClient.appdata.xml     
2026-07-16 17:45:17.000000000 +0200
@@ -90,6 +90,15 @@
   </content_rating>
 
   <releases>
+    <release version="5.1.5" date="2026-07-16">
+      <description>
+        <p>Bug-fix release. A database stored on a filesystem that does not 
implement POSIX file locks, most notably the Flatpak XDG document-portal path 
(/run/user/UID/doc/) that the file chooser hands back, could not be opened or 
created and failed with "Failed to acquire database lock: Function not 
implemented"; the lock file added in 5.1.4 is now treated as best-effort. This 
release also stops the secure-memory pool from reserving the whole 
locked-memory budget, which had left the GTK password entry unable to lock its 
own buffer on every unlock.</p>
+        <ul>
+          <li>FIX: a database stored on a filesystem without lock support (the 
Flatpak document portal, and some NFS/SMB mounts) could not be opened or 
created, failing with "Failed to acquire database lock: Function not 
implemented". Locking is now best-effort so the database opens normally on 
those filesystems, while real locking is unchanged everywhere else (#466)</li>
+          <li>FIX: the secure-memory pool consumed the whole RLIMIT_MEMLOCK 
budget, so the GTK password entry could not lock its own buffer and warned 
"couldn't lock 16384 bytes of memory (gtk): Cannot allocate memory", falling 
back to unlocked memory for the typed password on every unlock; the pool now 
leaves headroom for it (Debian #1141809)</li>
+        </ul>
+      </description>
+    </release>
     <release version="5.1.4" date="2026-07-10">
       <description>
         <p>Bug-fix release. Following the anonymous-token fix in 5.1.3, a 
database containing a token with an out-of-range digit count still refused to 
open, again locking users out of every other token. The load-time validator was 
stricter than the OTP engine and the app's own UI; the accepted ranges now 
match the engine (digits 4 to 10, period 1 to 120 seconds). Any token the 
engine still cannot use is set aside so the rest of the database opens, and is 
preserved for repair rather than dropped.</p>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/src/common/common.c 
new/OTPClient-5.1.5/src/common/common.c
--- old/OTPClient-5.1.4/src/common/common.c     2026-07-10 11:41:32.000000000 
+0200
+++ new/OTPClient-5.1.5/src/common/common.c     2026-07-16 17:45:17.000000000 
+0200
@@ -18,6 +18,31 @@
 
 
 gint32
+secmem_pool_from_limits (guint64  memlock_budget,
+                         gint32  *memlock_value)
+{
+    // Enough room for our full default pool plus headroom for GTK/libadwaita's
+    // password-entry secure buffer: hand out the default and report OK.
+    if (memlock_budget >= (guint64) DEFAULT_MEMLOCK_VALUE + 
SECMEM_HEADROOM_VALUE) {
+        *memlock_value = DEFAULT_MEMLOCK_VALUE;
+        return MEMLOCK_OK;
+    }
+
+    // Tighter budget: shrink our pool by SECMEM_HEADROOM_VALUE so the kernel 
still
+    // has locked-memory budget left for GTK's 16 KiB GtkPasswordEntryBuffer 
block
+    // (otherwise the app itself starves GTK and the unlock field can't be 
locked).
+    // If the budget is so small that reserving headroom would drop us below 
the
+    // floor, take what we can and let GTK warn rather than crippling 
ourselves.
+    if (memlock_budget > (guint64) SECMEM_HEADROOM_VALUE + 
MIN_SECMEM_POOL_VALUE) {
+        *memlock_value = (gint32) (memlock_budget - SECMEM_HEADROOM_VALUE);
+    } else {
+        *memlock_value = (gint32) memlock_budget;
+    }
+    return MEMLOCK_TOO_LOW;
+}
+
+
+gint32
 set_memlock_value (gint32 *memlock_value)
 {
     struct rlimit r;
@@ -26,14 +51,19 @@
         return MEMLOCK_ERR;
     }
 
-    if (r.rlim_cur < DEFAULT_MEMLOCK_VALUE) {
-        // memlock is less than the default value, so we need to warn the user 
that there might not be enough secmem available.
-        *memlock_value = (gint32) r.rlim_cur;
-        return MEMLOCK_TOO_LOW;
+    // Best-effort: raise the soft limit toward the hard limit so both our 
libgcrypt
+    // pool and GTK/libadwaita's password-entry secure buffer can be locked.
+    // Unprivileged processes may raise the soft limit up to the hard limit; 
ignore
+    // failures and fall back to whatever the kernel currently reports.
+    if (r.rlim_cur != RLIM_INFINITY && r.rlim_cur < r.rlim_max) {
+        struct rlimit raised = r;
+        raised.rlim_cur = r.rlim_max;
+        if (setrlimit (RLIMIT_MEMLOCK, &raised) == 0) {
+            r = raised;
+        }
     }
 
-    *memlock_value = DEFAULT_MEMLOCK_VALUE;
-    return MEMLOCK_OK;
+    return secmem_pool_from_limits ((guint64) r.rlim_cur, memlock_value);
 }
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/src/common/common.h 
new/OTPClient-5.1.5/src/common/common.h
--- old/OTPClient-5.1.4/src/common/common.h     2026-07-10 11:41:32.000000000 
+0200
+++ new/OTPClient-5.1.5/src/common/common.h     2026-07-16 17:45:17.000000000 
+0200
@@ -11,6 +11,8 @@
 #define MEMLOCK_OK                       2
 #define MEMLOCK_TOO_LOW                  3
 #define DEFAULT_MEMLOCK_VALUE     67108864 // 64 MiB
+#define SECMEM_HEADROOM_VALUE      1048576 // 1 MiB left unlocked below 
RLIMIT_MEMLOCK so GTK/libadwaita can still mlock the password-entry buffer
+#define MIN_SECMEM_POOL_VALUE      1048576 // 1 MiB floor for our own pool 
when the limit is too low to reserve headroom
 #define SECMEM_SIZE_THRESHOLD_RATIO   0.80
 #define SECMEM_REQUIRED_MULTIPLIER       3
 
@@ -43,6 +45,9 @@
 
 gint32            set_memlock_value (gint32             *memlock_value);
 
+gint32            secmem_pool_from_limits          (guint64             
memlock_budget,
+                                                  gint32             
*memlock_value);
+
 gchar            *init_libs                      (gint32              
max_file_size);
 
 gint              get_algo_int_from_str          (const gchar        *algo);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/src/common/db-common.c 
new/OTPClient-5.1.5/src/common/db-common.c
--- old/OTPClient-5.1.4/src/common/db-common.c  2026-07-10 11:41:32.000000000 
+0200
+++ new/OTPClient-5.1.5/src/common/db-common.c  2026-07-16 17:45:17.000000000 
+0200
@@ -26,6 +26,7 @@
 #ifdef OTPCLIENT_TESTING
 static gboolean test_fail_encrypt = FALSE;
 static gboolean test_fail_atomic_write = FALSE;
+static gboolean test_unsupported_lock = FALSE;
 
 void
 db_test_set_fail_encrypt (gboolean fail)
@@ -38,6 +39,12 @@
 {
     test_fail_atomic_write = fail;
 }
+
+void
+db_test_set_unsupported_lock (gboolean unsupported)
+{
+    test_unsupported_lock = unsupported;
+}
 #endif
 
 static gint32    get_db_version     (const gchar      *db_path,
@@ -299,6 +306,21 @@
 }
 
 
+/* Wrapper around flock() so tests can force the "filesystem does not support
+ * locking" path (see db_test_set_unsupported_lock). */
+static int
+db_try_flock (int fd)
+{
+#ifdef OTPCLIENT_TESTING
+    if (test_unsupported_lock) {
+        errno = ENOSYS;
+        return -1;
+    }
+#endif
+    return flock (fd, LOCK_EX | LOCK_NB);
+}
+
+
 static gboolean
 lock_db (const gchar *db_path,
          DbLock      *lock,
@@ -317,7 +339,24 @@
     }
 
     gint64 deadline = g_get_monotonic_time () + (2 * G_USEC_PER_SEC);
-    while (flock (lock->fd, LOCK_EX | LOCK_NB) != 0) {
+    while (db_try_flock (lock->fd) != 0) {
+        if (errno == ENOSYS || errno == EOPNOTSUPP) {
+            /* Some filesystems do not implement POSIX locks and fail with
+             * ENOSYS/EOPNOTSUPP, notably the Flatpak XDG document-portal FUSE
+             * mount (/run/user/<uid>/doc/) and some NFS/SMB setups. The lock 
is
+             * a best-effort guard against a second OTPClient instance writing
+             * concurrently, not a correctness requirement, so continue without
+             * it rather than making the database impossible to open (issue 
#466).
+             * Leave lock->fd open; unlock_db () cleans it up. Warn once so we 
do
+             * not spam on every write. */
+            static gboolean warned = FALSE;
+            if (!warned) {
+                g_warning ("Database lock not supported on this filesystem 
'%s'; "
+                           "continuing without a lock: %s", lock->path, 
g_strerror (errno));
+                warned = TRUE;
+            }
+            return TRUE;
+        }
         if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) {
             g_set_error (err, generic_error_gquark (), GENERIC_ERRCODE,
                          "Failed to acquire database lock '%s': %s", 
lock->path, g_strerror (errno));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/src/common/db-common.h 
new/OTPClient-5.1.5/src/common/db-common.h
--- old/OTPClient-5.1.4/src/common/db-common.h  2026-07-10 11:41:32.000000000 
+0200
+++ new/OTPClient-5.1.5/src/common/db-common.h  2026-07-16 17:45:17.000000000 
+0200
@@ -189,6 +189,7 @@
 #ifdef OTPCLIENT_TESTING
 void    db_test_set_fail_encrypt      (gboolean fail);
 void    db_test_set_fail_atomic_write (gboolean fail);
+void    db_test_set_unsupported_lock  (gboolean unsupported);
 #endif
 
 G_END_DECLS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/tests/CMakeLists.txt 
new/OTPClient-5.1.5/tests/CMakeLists.txt
--- old/OTPClient-5.1.4/tests/CMakeLists.txt    2026-07-10 11:41:32.000000000 
+0200
+++ new/OTPClient-5.1.5/tests/CMakeLists.txt    2026-07-16 17:45:17.000000000 
+0200
@@ -180,6 +180,20 @@
 target_link_libraries(test_field_bounds_roundtrip ${COMMON_LIBS})
 add_test(NAME field_bounds_roundtrip COMMAND test_field_bounds_roundtrip)
 
+add_executable(test_memlock_sizing
+        test_memlock_sizing.c
+        ${PROJECT_SOURCE_DIR}/src/common/common.c
+        ${PROJECT_SOURCE_DIR}/src/common/file-size.c
+        ${PROJECT_SOURCE_DIR}/src/common/gquarks.c
+        ${PROJECT_SOURCE_DIR}/src/common/otp-validation.c
+)
+otpclient_apply_target_settings(test_memlock_sizing)
+target_include_directories(test_memlock_sizing PRIVATE
+        ${PROJECT_SOURCE_DIR}/src/common
+)
+target_link_libraries(test_memlock_sizing ${COMMON_LIBS})
+add_test(NAME memlock_sizing COMMAND test_memlock_sizing)
+
 if(BUILD_GUI)
     add_executable(test_otp_entry
             test_otp_entry.c
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/tests/README.md 
new/OTPClient-5.1.5/tests/README.md
--- old/OTPClient-5.1.4/tests/README.md 2026-07-10 11:41:32.000000000 +0200
+++ new/OTPClient-5.1.5/tests/README.md 2026-07-16 17:45:17.000000000 +0200
@@ -83,3 +83,12 @@
 and that a database file which does contain such a token still opens - the 
valid
 tokens load while the broken ones are set aside and preserved across a
 save/reload instead of bricking the whole database.
+
+**`test_memlock_sizing`** is the regression guard for the locked-memory
+budgeting (Debian #1141809). It pins `secmem_pool_from_limits()`, the pure part
+of `set_memlock_value()`, so that otpclient never sizes its libgcrypt secure
+pool to the whole `RLIMIT_MEMLOCK` budget: it must always leave
+`SECMEM_HEADROOM_VALUE` unlocked so GTK/libadwaita can still mlock its 16 KiB
+password-entry buffer. It covers a generous budget (full 64 MiB pool), the
+`RLIM_INFINITY` case (no overflow), the threshold and floor boundaries, and the
+typical 8 MiB systemd limit that triggered the report.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/tests/test_db_transaction.c 
new/OTPClient-5.1.5/tests/test_db_transaction.c
--- old/OTPClient-5.1.4/tests/test_db_transaction.c     2026-07-10 
11:41:32.000000000 +0200
+++ new/OTPClient-5.1.5/tests/test_db_transaction.c     2026-07-16 
17:45:17.000000000 +0200
@@ -204,6 +204,38 @@
     cleanup_db_data (first, dir, path);
 }
 
+static void
+test_lock_unsupported_fallback (void)
+{
+    gchar *dir = NULL;
+    gchar *path = NULL;
+    DatabaseData *db_data = make_db_data (&dir, &path);
+
+    /* Simulate a filesystem whose flock() fails with ENOSYS, e.g. the Flatpak
+     * document-portal FUSE mount (issue #466). The transaction must still
+     * succeed and write the database instead of aborting. */
+    db_test_set_unsupported_lock (TRUE);
+
+    /* The fallback warns exactly once per process; expect it on the first 
write. */
+    g_test_expect_message (NULL, G_LOG_LEVEL_WARNING, "*lock not supported*");
+
+    GError *err = NULL;
+    g_assert_true (db_transaction (db_data, append_token_mutation, NULL, 
&err));
+    g_assert_no_error (err);
+    g_test_assert_expected_messages ();
+    g_assert_true (g_file_test (path, G_FILE_TEST_EXISTS));
+    g_assert_cmpint ((int) json_array_size (db_data->in_memory_json_data), ==, 
2);
+
+    /* A second write must also succeed and must NOT warn again (warn-once);
+     * an unexpected warning here would be fatal under the test harness. */
+    g_assert_true (db_transaction (db_data, append_token_mutation, NULL, 
&err));
+    g_assert_no_error (err);
+    g_assert_cmpint ((int) json_array_size (db_data->in_memory_json_data), ==, 
3);
+
+    db_test_set_unsupported_lock (FALSE);
+    cleanup_db_data (db_data, dir, path);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -216,6 +248,7 @@
     g_test_add_func ("/db-transaction/password-change-failure", 
test_password_change_failure_restores_key);
     g_test_add_func ("/db-transaction/kdf-failure", 
test_kdf_failure_restores_params);
     g_test_add_func ("/db-transaction/stale-snapshot", 
test_stale_snapshot_rejected);
+    g_test_add_func ("/db-transaction/lock-unsupported-fallback", 
test_lock_unsupported_fallback);
 
     return g_test_run ();
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/OTPClient-5.1.4/tests/test_memlock_sizing.c 
new/OTPClient-5.1.5/tests/test_memlock_sizing.c
--- old/OTPClient-5.1.4/tests/test_memlock_sizing.c     1970-01-01 
01:00:00.000000000 +0100
+++ new/OTPClient-5.1.5/tests/test_memlock_sizing.c     2026-07-16 
17:45:17.000000000 +0200
@@ -0,0 +1,117 @@
+#include <glib.h>
+#include "common.h"
+
+/* secmem_pool_from_limits() turns a locked-memory budget (RLIMIT_MEMLOCK) into
+ * the size of the libgcrypt secure pool otpclient asks for. The invariant that
+ * matters for bug #1141809 is that it must never claim the whole budget: it 
has
+ * to leave at least SECMEM_HEADROOM_VALUE unlocked so GTK/libadwaita can still
+ * mlock its 16 KiB GtkPasswordEntryBuffer block for the unlock field. Before 
the
+ * fix the app locked 100% of the budget and starved GTK, producing the 
reported
+ * "couldn't lock 16384 bytes of memory (gtk)" warning. */
+
+#define MIB (1048576ULL)
+
+static void
+test_budget_above_threshold_gets_default (void)
+{
+    /* Budget comfortably above default pool + headroom: full 64 MiB, OK. */
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (128 * MIB, &pool), ==, 
MEMLOCK_OK);
+    g_assert_cmpint (pool, ==, DEFAULT_MEMLOCK_VALUE);
+}
+
+static void
+test_budget_exactly_at_threshold_gets_default (void)
+{
+    /* Exactly default + headroom is the smallest budget that still yields the
+     * full pool without eating into the reserve. */
+    guint64 budget = (guint64) DEFAULT_MEMLOCK_VALUE + SECMEM_HEADROOM_VALUE;
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (budget, &pool), ==, MEMLOCK_OK);
+    g_assert_cmpint (pool, ==, DEFAULT_MEMLOCK_VALUE);
+}
+
+static void
+test_infinity_gets_default (void)
+{
+    /* RLIM_INFINITY reaches the helper as a very large value; it must not
+     * overflow the subtraction and must yield the default pool. */
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (G_MAXUINT64, &pool), ==, 
MEMLOCK_OK);
+    g_assert_cmpint (pool, ==, DEFAULT_MEMLOCK_VALUE);
+}
+
+static void
+test_just_below_threshold_reserves_headroom (void)
+{
+    /* One byte below the threshold: we no longer get the full default, we get 
a
+     * pool shrunk by exactly the headroom, and the status drops to TOO_LOW. */
+    guint64 budget = (guint64) DEFAULT_MEMLOCK_VALUE + SECMEM_HEADROOM_VALUE - 
1;
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (budget, &pool), ==, 
MEMLOCK_TOO_LOW);
+    g_assert_cmpint (pool, ==, (gint32) (budget - SECMEM_HEADROOM_VALUE));
+    g_assert_cmpuint (budget - (guint64) pool, >=, (guint64) 
SECMEM_HEADROOM_VALUE);
+}
+
+static void
+test_typical_8mib_leaves_headroom (void)
+{
+    /* The reporter's case: a small systemd DefaultLimitMEMLOCK. The pool must 
be
+     * shrunk so at least the headroom (>> GTK's 16 KiB) stays lockable. */
+    guint64 budget = 8 * MIB;
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (budget, &pool), ==, 
MEMLOCK_TOO_LOW);
+    g_assert_cmpint (pool, ==, (gint32) (budget - SECMEM_HEADROOM_VALUE));
+    g_assert_cmpuint (budget - (guint64) pool, >=, 16384); /* GTK's 16 KiB 
block fits */
+}
+
+static void
+test_exactly_64mib_still_reserves (void)
+{
+    /* A limit of exactly the old default now reserves headroom instead of
+     * claiming all of it. The old code returned the full 64 MiB here, which is
+     * precisely what left GTK nothing to lock. */
+    guint64 budget = DEFAULT_MEMLOCK_VALUE;
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (budget, &pool), ==, 
MEMLOCK_TOO_LOW);
+    g_assert_cmpint (pool, ==, (gint32) (budget - SECMEM_HEADROOM_VALUE));
+}
+
+static void
+test_floor_budget_uses_all (void)
+{
+    /* When the budget is too small to carve out headroom without dropping 
below
+     * the floor, use what we have (a small locked pool beats none) and report
+     * TOO_LOW. GTK may still warn here, which is unavoidable at this limit. */
+    guint64 budget = (guint64) SECMEM_HEADROOM_VALUE + MIN_SECMEM_POOL_VALUE; 
/* boundary, not > */
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (budget, &pool), ==, 
MEMLOCK_TOO_LOW);
+    g_assert_cmpint (pool, ==, (gint32) budget);
+}
+
+static void
+test_just_above_floor_reserves (void)
+{
+    /* One byte above the floor boundary flips to the reserve branch. */
+    guint64 budget = (guint64) SECMEM_HEADROOM_VALUE + MIN_SECMEM_POOL_VALUE + 
1;
+    gint32 pool = -1;
+    g_assert_cmpint (secmem_pool_from_limits (budget, &pool), ==, 
MEMLOCK_TOO_LOW);
+    g_assert_cmpint (pool, ==, (gint32) (budget - SECMEM_HEADROOM_VALUE));
+}
+
+int
+main (int argc, char **argv)
+{
+    g_test_init (&argc, &argv, NULL);
+
+    g_test_add_func ("/memlock-sizing/above-threshold-default", 
test_budget_above_threshold_gets_default);
+    g_test_add_func ("/memlock-sizing/at-threshold-default",    
test_budget_exactly_at_threshold_gets_default);
+    g_test_add_func ("/memlock-sizing/infinity-default",        
test_infinity_gets_default);
+    g_test_add_func ("/memlock-sizing/just-below-threshold",    
test_just_below_threshold_reserves_headroom);
+    g_test_add_func ("/memlock-sizing/typical-8mib",            
test_typical_8mib_leaves_headroom);
+    g_test_add_func ("/memlock-sizing/exactly-64mib",           
test_exactly_64mib_still_reserves);
+    g_test_add_func ("/memlock-sizing/floor-uses-all",          
test_floor_budget_uses_all);
+    g_test_add_func ("/memlock-sizing/just-above-floor",        
test_just_above_floor_reserves);
+
+    return g_test_run ();
+}

Reply via email to