blob: a229a34a2959004e153ca14ffdb83ebce20a3e3a [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001--- a/src/mp/mp_stat.c
2+++ b/src/mp/mp_stat.c
3@@ -87,6 +87,13 @@ __memp_stat(env, gspp, fspp, flags)
4 u_int32_t i;
5 uintmax_t tmp_wait, tmp_nowait;
6
7+ /*
8+ * The array holding the lengths related to the buffer allocated for *fspp.
9+ * The first element of the array holds the number of entries allocated.
10+ * The second element of the array holds the total number of bytes allocated.
11+ */
12+ u_int32_t fsp_len[2];
13+
14 dbmp = env->mp_handle;
15 mp = dbmp->reginfo[0].primary;
16
17@@ -193,32 +200,53 @@ __memp_stat(env, gspp, fspp, flags)
18 if (fspp != NULL) {
19 *fspp = NULL;
20
21- /* Count the MPOOLFILE structures. */
22- i = 0;
23- len = 0;
24- if ((ret = __memp_walk_files(env,
25- mp, __memp_count_files, &len, &i, flags)) != 0)
26- return (ret);
27-
28- if (i == 0)
29- return (0);
30- len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */
31+ while (*fspp == NULL) {
32+ /* Count the MPOOLFILE structures. */
33+ i = 0;
34+ /*
35+ * Allow space for the first __memp_get_files() to align the
36+ * structure array to uintmax_t, DB_MPOOL_STAT's most
37+ * restrictive field. [#23150]
38+ */
39+ len = sizeof(uintmax_t);
40+ if ((ret = __memp_walk_files(env,
41+ mp, __memp_count_files, &len, &i, flags)) != 0)
42+ return (ret);
43+
44+ if (i == 0)
45+ return (0);
46+
47+ /*
48+ * Copy the number of DB_MPOOL_FSTAT entries and the number of
49+ * bytes allocated for them into fsp_len. Do not count the space
50+ * reserved for allignment.
51+ */
52+ fsp_len[0] = i;
53+ fsp_len[1] = len - sizeof(uintmax_t);
54
55- /* Allocate space */
56- if ((ret = __os_umalloc(env, len, fspp)) != 0)
57- return (ret);
58+ len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */
59
60- tfsp = *fspp;
61- *tfsp = NULL;
62+ /* Allocate space */
63+ if ((ret = __os_umalloc(env, len, fspp)) != 0)
64+ return (ret);
65
66- /*
67- * Files may have been opened since we counted, don't walk
68- * off the end of the allocated space.
69- */
70- if ((ret = __memp_walk_files(env,
71- mp, __memp_get_files, &tfsp, &i, flags)) != 0)
72- return (ret);
73+ tfsp = *fspp;
74+ *tfsp = NULL;
75
76+ /*
77+ * Files may have been opened since we counted, if we walk off
78+ * the end of the allocated space specified in fsp_len, retry.
79+ */
80+ if ((ret = __memp_walk_files(env,
81+ mp, __memp_get_files, &tfsp, fsp_len, flags)) != 0) {
82+ if (ret == DB_BUFFER_SMALL) {
83+ __os_ufree(env, *fspp);
84+ *fspp = NULL;
85+ tfsp = NULL;
86+ } else
87+ return (ret);
88+ }
89+ }
90 *++tfsp = NULL;
91 }
92
93@@ -286,28 +314,35 @@ __memp_count_files(env, mfp, argp, count
94 * for the text file names.
95 */
96 static int
97-__memp_get_files(env, mfp, argp, countp, flags)
98+__memp_get_files(env, mfp, argp, fsp_len, flags)
99 ENV *env;
100 MPOOLFILE *mfp;
101 void *argp;
102- u_int32_t *countp;
103+ u_int32_t fsp_len[];
104 u_int32_t flags;
105 {
106 DB_MPOOL *dbmp;
107 DB_MPOOL_FSTAT **tfsp, *tstruct;
108 char *name, *tname;
109- size_t nlen;
110+ size_t nlen, tlen;
111
112- if (*countp == 0)
113- return (0);
114+ /* We walked through more files than argp was allocated for. */
115+ if (fsp_len[0] == 0)
116+ return DB_BUFFER_SMALL;
117
118 dbmp = env->mp_handle;
119 tfsp = *(DB_MPOOL_FSTAT ***)argp;
120
121 if (*tfsp == NULL) {
122- /* Add 1 to count because we need to skip over the NULL. */
123- tstruct = (DB_MPOOL_FSTAT *)(tfsp + *countp + 1);
124- tname = (char *)(tstruct + *countp);
125+ /*
126+ * Add 1 to count because to skip over the NULL end marker.
127+ * Align it further for DB_MPOOL_STAT's most restrictive field
128+ * because uintmax_t might require stricter alignment than
129+ * pointers; e.g., IP32 LL64 SPARC. [#23150]
130+ */
131+ tstruct = (DB_MPOOL_FSTAT *)&tfsp[fsp_len[0] + 1];
132+ tstruct = ALIGNP_INC(tstruct, sizeof(uintmax_t));
133+ tname = (char *)&tstruct[fsp_len[0]];
134 *tfsp = tstruct;
135 } else {
136 tstruct = *tfsp + 1;
137@@ -317,6 +352,15 @@ __memp_get_files(env, mfp, argp, countp,
138
139 name = __memp_fns(dbmp, mfp);
140 nlen = strlen(name) + 1;
141+
142+ /* The space required for file names is larger than argp was allocated for. */
143+ tlen = sizeof(DB_MPOOL_FSTAT *) + sizeof(DB_MPOOL_FSTAT) + nlen;
144+ if (fsp_len[1] < tlen)
145+ return DB_BUFFER_SMALL;
146+ else
147+ /* Count down the number of bytes left in argp. */
148+ fsp_len[1] -= tlen;
149+
150 memcpy(tname, name, nlen);
151 memcpy(tstruct, &mfp->stat, sizeof(mfp->stat));
152 tstruct->file_name = tname;
153@@ -325,7 +369,9 @@ __memp_get_files(env, mfp, argp, countp,
154 tstruct->st_pagesize = mfp->pagesize;
155
156 *(DB_MPOOL_FSTAT ***)argp = tfsp;
157- (*countp)--;
158+
159+ /* Count down the number of entries left in argp. */
160+ fsp_len[0]--;
161
162 if (LF_ISSET(DB_STAT_CLEAR))
163 memset(&mfp->stat, 0, sizeof(mfp->stat));
164--- a/src/mp/mp_sync.c
165+++ b/src/mp/mp_sync.c
166@@ -57,11 +57,13 @@ __memp_walk_files(env, mp, func, arg, co
167 if ((t_ret = func(env,
168 mfp, arg, countp, flags)) != 0 && ret == 0)
169 ret = t_ret;
170- if (ret != 0 && !LF_ISSET(DB_STAT_MEMP_NOERROR))
171+ if (ret != 0 &&
172+ (!LF_ISSET(DB_STAT_MEMP_NOERROR) || ret == DB_BUFFER_SMALL))
173 break;
174 }
175 MUTEX_UNLOCK(env, hp->mtx_hash);
176- if (ret != 0 && !LF_ISSET(DB_STAT_MEMP_NOERROR))
177+ if (ret != 0 &&
178+ (!LF_ISSET(DB_STAT_MEMP_NOERROR) || ret == DB_BUFFER_SMALL))
179 break;
180 }
181 return (ret);