File: ghash-Handle-all-table-sizes-in-iterator.patch

package info (click to toggle)
glib2.0 2.86.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 73,060 kB
  • sloc: ansic: 544,382; python: 9,702; sh: 1,612; xml: 1,482; perl: 1,222; cpp: 535; makefile: 321; javascript: 11
file content (97 lines) | stat: -rw-r--r-- 3,526 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
From: Tobias Stoeckmann <tobias@stoeckmann.org>
Date: Mon, 25 Aug 2025 22:17:31 +0200
Subject: ghash: Handle all table sizes in iterator

A table size of 2**31 cannot be represented in a gint. Adjust
RealIter to use a guint for its current position to support the largest
power of two possible for a hash table size.

This makes sure that g_hash_table_iter_next does not trigger a signed
integer overflow, which would eventually lead to an out of boundary
read.

With input by Philip Withnall.

Bug: https://gitlab.gnome.org/GNOME/glib/-/issues/672
Origin: upstream, 2.86.1, commit:7367c518f1ed9f06e11c336e0fc28bfb1547a652
---
 glib/ghash.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/glib/ghash.c b/glib/ghash.c
index b170a84..352098c 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -189,6 +189,12 @@
 #define HASH_IS_TOMBSTONE(h_) ((h_) == TOMBSTONE_HASH_VALUE)
 #define HASH_IS_REAL(h_) ((h_) >= 2)
 
+/* The hash table can never have this as a valid position, as
+ * hash tables are allocated as a power of two, and the allocation
+ * required for this position would overflow. So we’re safe to use
+ * it to represent an invalid iter position. */
+#define ITER_POSITION_INVALID G_MAXUINT
+
 /* If int is smaller than void * on our arch, we start out with
  * int-sized keys and values and resize to pointer-sized entries as
  * needed. This saves a good amount of memory when the HT is being
@@ -237,7 +243,7 @@ typedef struct
   GHashTable  *hash_table;
   gpointer     dummy1;
   gpointer     dummy2;
-  gint         position;
+  guint        position;
   gboolean     dummy3;
   gintptr      version;
 } RealIter;
@@ -1100,7 +1106,7 @@ g_hash_table_iter_init (GHashTableIter *iter,
   g_return_if_fail (hash_table != NULL);
 
   ri->hash_table = hash_table;
-  ri->position = -1;
+  ri->position = ITER_POSITION_INVALID;
 #ifndef G_DISABLE_ASSERT
   ri->version = hash_table->version;
 #endif
@@ -1126,20 +1132,20 @@ g_hash_table_iter_next (GHashTableIter *iter,
                         gpointer       *value)
 {
   RealIter *ri = (RealIter *) iter;
-  gint position;
+  guint position;
 
   g_return_val_if_fail (iter != NULL, FALSE);
 #ifndef G_DISABLE_ASSERT
   g_return_val_if_fail (ri->version == ri->hash_table->version, FALSE);
 #endif
-  g_return_val_if_fail (ri->position < (gssize) ri->hash_table->size, FALSE);
+  g_return_val_if_fail (ri->position < ri->hash_table->size || ri->position == ITER_POSITION_INVALID, FALSE);
 
   position = ri->position;
 
   do
     {
       position++;
-      if (position >= (gssize) ri->hash_table->size)
+      if (position >= ri->hash_table->size)
         {
           ri->position = position;
           return FALSE;
@@ -1181,7 +1187,7 @@ iter_remove_or_steal (RealIter *ri, gboolean notify)
 #ifndef G_DISABLE_ASSERT
   g_return_if_fail (ri->version == ri->hash_table->version);
 #endif
-  g_return_if_fail (ri->position >= 0);
+  g_return_if_fail (ri->position != ITER_POSITION_INVALID);
   g_return_if_fail ((gsize) ri->position < ri->hash_table->size);
 
   g_hash_table_remove_node (ri->hash_table, ri->position, notify);
@@ -1365,7 +1371,7 @@ g_hash_table_iter_replace (GHashTableIter *iter,
 #ifndef G_DISABLE_ASSERT
   g_return_if_fail (ri->version == ri->hash_table->version);
 #endif
-  g_return_if_fail (ri->position >= 0);
+  g_return_if_fail (ri->position != ITER_POSITION_INVALID);
   g_return_if_fail ((gsize) ri->position < ri->hash_table->size);
 
   node_hash = ri->hash_table->hashes[ri->position];