This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Improve check against integer wraparound in hcreate_r [BZ #18240]
- From: Paul Eggert <eggert at cs dot ucla dot edu>
- To: Florian Weimer <fw at deneb dot enyo dot de>
- Cc: Florian Weimer <fweimer at redhat dot com>, GNU C Library <libc-alpha at sourceware dot org>, Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- Date: Mon, 25 Jan 2016 16:06:27 -0800
- Subject: Re: [PATCH] Improve check against integer wraparound in hcreate_r [BZ #18240]
- Authentication-results: sourceware.org; auth=none
- References: <56A210C4 dot 80609 at redhat dot com> <56A42D78 dot 1030506 at cs dot ucla dot edu> <877fixs9or dot fsf at mid dot deneb dot enyo dot de>
On 01/25/2016 12:09 PM, Florian Weimer wrote:
- while (div * div < number && number % div != 0)
+ while (div * (unsigned long long) div < number && number % div != 0)
Good catch. But better yet, get rid of the '*' so that we needn't worry
about whether the multiplication overflows. On typical platforms the
divide instruction that the '%' is already doing will give us the
information we need, so this is faster anyway. Something like the
attached (untested) patch.
diff --git a/misc/hsearch_r.c b/misc/hsearch_r.c
index f6f16ed..1fca6b3 100644
--- a/misc/hsearch_r.c
+++ b/misc/hsearch_r.c
@@ -46,15 +46,12 @@ static int
isprime (unsigned int number)
{
/* no even number will be passed */
- unsigned int div = 3;
-
- while (div * div < number && number % div != 0)
- div += 2;
-
- return number % div != 0;
+ for (unsigned int div = 3; div <= number / div; div += 2)
+ if (number % div == 0)
+ return 0;
+ return 1;
}
-
/* Before using the hash table we must allocate memory for it.
Test for an existing table are done. We allocate one element
more as the found prime number says. This is done for more effective
@@ -71,13 +68,6 @@ __hcreate_r (size_t nel, struct hsearch_data *htab)
return 0;
}
- if (nel >= SIZE_MAX / sizeof (_ENTRY))
- {
- __set_errno (ENOMEM);
- return 0;
- }
-
-
/* There is still another table active. Return with error. */
if (htab->table != NULL)
return 0;
@@ -86,10 +76,19 @@ __hcreate_r (size_t nel, struct hsearch_data *htab)
use will not work. */
if (nel < 3)
nel = 3;
- /* Change nel to the first prime number not smaller as nel. */
- nel |= 1; /* make odd */
- while (!isprime (nel))
- nel += 2;
+
+ /* Change nel to the first prime number in the range [nel, UINT_MAX - 2],
+ The '- 2' means 'nel += 2' cannot overflow. */
+ for (nel |= 1; ; nel += 2)
+ {
+ if (UINT_MAX - 2 < nel)
+ {
+ __set_errno (ENOMEM);
+ return 0;
+ }
+ if (isprime (nel))
+ break;
+ }
htab->size = nel;
htab->filled = 0;