| --- a/src/mp/mp_stat.c |
| +++ b/src/mp/mp_stat.c |
| @@ -87,6 +87,13 @@ __memp_stat(env, gspp, fspp, flags) |
| u_int32_t i; |
| uintmax_t tmp_wait, tmp_nowait; |
| |
| + /* |
| + * The array holding the lengths related to the buffer allocated for *fspp. |
| + * The first element of the array holds the number of entries allocated. |
| + * The second element of the array holds the total number of bytes allocated. |
| + */ |
| + u_int32_t fsp_len[2]; |
| + |
| dbmp = env->mp_handle; |
| mp = dbmp->reginfo[0].primary; |
| |
| @@ -193,32 +200,53 @@ __memp_stat(env, gspp, fspp, flags) |
| if (fspp != NULL) { |
| *fspp = NULL; |
| |
| - /* Count the MPOOLFILE structures. */ |
| - i = 0; |
| - len = 0; |
| - if ((ret = __memp_walk_files(env, |
| - mp, __memp_count_files, &len, &i, flags)) != 0) |
| - return (ret); |
| - |
| - if (i == 0) |
| - return (0); |
| - len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */ |
| + while (*fspp == NULL) { |
| + /* Count the MPOOLFILE structures. */ |
| + i = 0; |
| + /* |
| + * Allow space for the first __memp_get_files() to align the |
| + * structure array to uintmax_t, DB_MPOOL_STAT's most |
| + * restrictive field. [#23150] |
| + */ |
| + len = sizeof(uintmax_t); |
| + if ((ret = __memp_walk_files(env, |
| + mp, __memp_count_files, &len, &i, flags)) != 0) |
| + return (ret); |
| + |
| + if (i == 0) |
| + return (0); |
| + |
| + /* |
| + * Copy the number of DB_MPOOL_FSTAT entries and the number of |
| + * bytes allocated for them into fsp_len. Do not count the space |
| + * reserved for allignment. |
| + */ |
| + fsp_len[0] = i; |
| + fsp_len[1] = len - sizeof(uintmax_t); |
| |
| - /* Allocate space */ |
| - if ((ret = __os_umalloc(env, len, fspp)) != 0) |
| - return (ret); |
| + len += sizeof(DB_MPOOL_FSTAT *); /* Trailing NULL */ |
| |
| - tfsp = *fspp; |
| - *tfsp = NULL; |
| + /* Allocate space */ |
| + if ((ret = __os_umalloc(env, len, fspp)) != 0) |
| + return (ret); |
| |
| - /* |
| - * Files may have been opened since we counted, don't walk |
| - * off the end of the allocated space. |
| - */ |
| - if ((ret = __memp_walk_files(env, |
| - mp, __memp_get_files, &tfsp, &i, flags)) != 0) |
| - return (ret); |
| + tfsp = *fspp; |
| + *tfsp = NULL; |
| |
| + /* |
| + * Files may have been opened since we counted, if we walk off |
| + * the end of the allocated space specified in fsp_len, retry. |
| + */ |
| + if ((ret = __memp_walk_files(env, |
| + mp, __memp_get_files, &tfsp, fsp_len, flags)) != 0) { |
| + if (ret == DB_BUFFER_SMALL) { |
| + __os_ufree(env, *fspp); |
| + *fspp = NULL; |
| + tfsp = NULL; |
| + } else |
| + return (ret); |
| + } |
| + } |
| *++tfsp = NULL; |
| } |
| |
| @@ -286,28 +314,35 @@ __memp_count_files(env, mfp, argp, count |
| * for the text file names. |
| */ |
| static int |
| -__memp_get_files(env, mfp, argp, countp, flags) |
| +__memp_get_files(env, mfp, argp, fsp_len, flags) |
| ENV *env; |
| MPOOLFILE *mfp; |
| void *argp; |
| - u_int32_t *countp; |
| + u_int32_t fsp_len[]; |
| u_int32_t flags; |
| { |
| DB_MPOOL *dbmp; |
| DB_MPOOL_FSTAT **tfsp, *tstruct; |
| char *name, *tname; |
| - size_t nlen; |
| + size_t nlen, tlen; |
| |
| - if (*countp == 0) |
| - return (0); |
| + /* We walked through more files than argp was allocated for. */ |
| + if (fsp_len[0] == 0) |
| + return DB_BUFFER_SMALL; |
| |
| dbmp = env->mp_handle; |
| tfsp = *(DB_MPOOL_FSTAT ***)argp; |
| |
| if (*tfsp == NULL) { |
| - /* Add 1 to count because we need to skip over the NULL. */ |
| - tstruct = (DB_MPOOL_FSTAT *)(tfsp + *countp + 1); |
| - tname = (char *)(tstruct + *countp); |
| + /* |
| + * Add 1 to count because to skip over the NULL end marker. |
| + * Align it further for DB_MPOOL_STAT's most restrictive field |
| + * because uintmax_t might require stricter alignment than |
| + * pointers; e.g., IP32 LL64 SPARC. [#23150] |
| + */ |
| + tstruct = (DB_MPOOL_FSTAT *)&tfsp[fsp_len[0] + 1]; |
| + tstruct = ALIGNP_INC(tstruct, sizeof(uintmax_t)); |
| + tname = (char *)&tstruct[fsp_len[0]]; |
| *tfsp = tstruct; |
| } else { |
| tstruct = *tfsp + 1; |
| @@ -317,6 +352,15 @@ __memp_get_files(env, mfp, argp, countp, |
| |
| name = __memp_fns(dbmp, mfp); |
| nlen = strlen(name) + 1; |
| + |
| + /* The space required for file names is larger than argp was allocated for. */ |
| + tlen = sizeof(DB_MPOOL_FSTAT *) + sizeof(DB_MPOOL_FSTAT) + nlen; |
| + if (fsp_len[1] < tlen) |
| + return DB_BUFFER_SMALL; |
| + else |
| + /* Count down the number of bytes left in argp. */ |
| + fsp_len[1] -= tlen; |
| + |
| memcpy(tname, name, nlen); |
| memcpy(tstruct, &mfp->stat, sizeof(mfp->stat)); |
| tstruct->file_name = tname; |
| @@ -325,7 +369,9 @@ __memp_get_files(env, mfp, argp, countp, |
| tstruct->st_pagesize = mfp->pagesize; |
| |
| *(DB_MPOOL_FSTAT ***)argp = tfsp; |
| - (*countp)--; |
| + |
| + /* Count down the number of entries left in argp. */ |
| + fsp_len[0]--; |
| |
| if (LF_ISSET(DB_STAT_CLEAR)) |
| memset(&mfp->stat, 0, sizeof(mfp->stat)); |
| --- a/src/mp/mp_sync.c |
| +++ b/src/mp/mp_sync.c |
| @@ -57,11 +57,13 @@ __memp_walk_files(env, mp, func, arg, co |
| if ((t_ret = func(env, |
| mfp, arg, countp, flags)) != 0 && ret == 0) |
| ret = t_ret; |
| - if (ret != 0 && !LF_ISSET(DB_STAT_MEMP_NOERROR)) |
| + if (ret != 0 && |
| + (!LF_ISSET(DB_STAT_MEMP_NOERROR) || ret == DB_BUFFER_SMALL)) |
| break; |
| } |
| MUTEX_UNLOCK(env, hp->mtx_hash); |
| - if (ret != 0 && !LF_ISSET(DB_STAT_MEMP_NOERROR)) |
| + if (ret != 0 && |
| + (!LF_ISSET(DB_STAT_MEMP_NOERROR) || ret == DB_BUFFER_SMALL)) |
| break; |
| } |
| return (ret); |