Richard Guenther wrote: > On Thu, Apr 19, 2012 at 2:13 PM, Jim Meyering <j...@meyering.net> wrote: >> Richard Guenther wrote: >>> On Thu, Apr 19, 2012 at 12:42 PM, Jim Meyering <j...@meyering.net> wrote: >>>> Found by inspection. >>>> Seeing this strncpy use without the usual following NUL-termination, >>>> my reflex was that it was a buffer overrun candidate, but then I >>>> realized this is gcc, so that's not very likely. >>>> Looking a little harder, I saw the preceding strlen >= sizeof buf test, >>>> which means there is no risk of overrun. >>>> >>>> That preceding test means the use of strncpy is misleading, since >>>> with that there is no risk of the name being too long for the buffer, >>>> and hence no reason to use strncpy. >>>> One way to make the code clearer is to use strcpy, as done below. >>>> An alternative is to use memcpy (buf, m->name, strlen (m->name) + 1). >> >> Thanks for the quick feedback. >> >>> Without a comment before the strcpy this isn't any more clear than >> >> Good point. >> How about with this folded in? >> >> diff --git a/gcc/genmodes.c b/gcc/genmodes.c >> index f786258..3833017 100644 >> --- a/gcc/genmodes.c >> +++ b/gcc/genmodes.c >> @@ -452,6 +452,7 @@ make_complex_modes (enum mode_class cl, >> if (cl == MODE_FLOAT) >> { >> char *p, *q = 0; >> + /* We verified above that m->name+NUL fits in buf. */ >> strcpy (buf, m->name); >> p = strchr (buf, 'F'); >> if (p == 0) > > That's better. Or even cache the strlen result and use memcpy here > as Jakub suggested. > >>> when using strncpy. Also your issue with the terminating NUL is >>> still present for the snprintf call done later (in fact the code looks like >>> it can be optimized, avoiding the strcpy in the path to the snprintf). >> >> Isn't it different with snprintf? >> While strncpy does *NOT* necessarily NUL-terminate, >> snprintf explicitly does, always. > > Sure, my point was that the > > if (strlen (m->name) >= sizeof buf) > { > error ("%s:%d:mode name \"%s\" is too long", > m->file, m->line, m->name); > continue; > } > > check does not account for the (conditional) prepending of 'C' and the > snprintf would silently discard the last character of the name.
Yes, you're right. It's good to avoid snprintf and its truncation, too. >> IMHO, if you'd like to avoid the duplication in the strcpy/snprintf >> path, that deserves to be a different change. > > Sure. > > The patch is ok with caching strlen and using memcpy. Like this, I presume: [alternatively, declare and compute m_len on a separate line, just before the comparison: size_t m_len = strlen (m->name); I'd actually prefer that, but don't know if decl-after-stmt is ok here. ] 2012-04-19 Jim Meyering <meyer...@redhat.com> genmodes: remove misleading use of strncpy * genmodes.c (make_complex_modes): Avoid unnecessary use of strncpy. We verified above that the string(including trailing NUL) fits in buf, so just use memcpy. diff --git a/gcc/genmodes.c b/gcc/genmodes.c index 8b6f5bc..484a6ac 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -1,5 +1,5 @@ /* Generate the machine mode enumeration and associated tables. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -435,11 +435,13 @@ make_complex_modes (enum mode_class cl, for (m = modes[cl]; m; m = m->next) { + size_t m_len; + /* Skip BImode. FIXME: BImode probably shouldn't be MODE_INT. */ if (m->precision == 1) continue; - if (strlen (m->name) >= sizeof buf) + if ((m_len = strlen (m->name)) >= sizeof buf) { error ("%s:%d:mode name \"%s\" is too long", m->file, m->line, m->name); @@ -452,7 +454,8 @@ make_complex_modes (enum mode_class cl, if (cl == MODE_FLOAT) { char *p, *q = 0; - strncpy (buf, m->name, sizeof buf); + /* We verified above that m->name+NUL fits in buf. */ + memcpy (buf, m->name, m_len + 1); p = strchr (buf, 'F'); if (p == 0) q = strchr (buf, 'D'); -- 1.7.10.208.gb4267