> Yes, this is a bug. In ascii2utf, this line: > > if (utfmax > 0) { > > should be replaced with this: > > if (*s && utfmax > 0) { Ah, I see. Now it makes sense what the function is trying to do. How about the following simplification instead: (Released to the public domain, copyright abandoned, have fun...) /* * helper routine for returning string descriptors in UTF-16LE * input can actually be ISO-8859-1; ASCII is its 7-bit subset. * @s: Null-terminated ASCII (actually ISO-8859-1) string * @utf: Buffer for UTF-16LE output * @utfmax: Length (in bytes; may be odd) of utf buffer. * * The return value is the number of bytes filled in: 2*strlen(s) or * utfmax, whichever is less. */ static unsigned ascii2utf(char const *s, u8 *utf, unsigned utfmax) { u8 * const utf0 = utf; while (*s && utfmax--) { *utf++ = *s++; if (!utfmax--) break; *utf++ = 0; } return (unsigned)(utf - utf0); } You could also re-jigger rh_string() to just pass the cd->self.bus_name and hcd->product_desc strings to ascii2utf() by reference rather than strlcpy()ing them. I also was worried that rh_string would leak data from the uninitialized stack buffer if id > 3. It turns out that that can't happen, but it sure got my heart rate going for a bit... static unsigned rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) { char buf[100]; char const *s; unsigned slen; // language ids switch (id) { case 0: /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ static char const langids[4] = {4, 3, 0x09, 0x04}; if (len > 4) len = 4; memcpy(data, langids, len); return len; case 1: /* Serial number */ s = hcd->self.bus_name; break; case 2: /* Product name */ s = hcd->product_desc; break; case 3: /* Manufacturer */ snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, init_utsname()->release, hcd->driver->description); s = buf; break; default: /* Can't happen; caller guarantees it */ return 0; } slen = strlen(s); if (slen > 126) /* Should never happen, but make sure */ slen = 126; switch (len) { /* All cases fall through */ default: len = 2 + ascii2utf(s, data + 2, len - 2); case 2: data [1] = 3; /* Descriptor type == string */ case 1: data [0] = 2 * (slen + 1); /* Total descriptor length */ case 0: ; /* Compiler wants a statement here */ } return len; } You could also refactor the code to fill in the first 2 bytes inside ascii2utf(). That cleans things up a lot: /* * helper routine for returning string descriptors in UTF-16LE * input can actually be ISO-8859-1; ASCII is its 7-bit subset. * @s: Null-terminated ASCII (actually ISO-8859-1) string * @utf: Buffer for USB string descritpro (header + UTF-16LE) * @utfmax: Length (in bytes; may be odd) of utf buffer. * * The return value is the number of bytes filled in: 2 + 2*strlen(s) or * utfmax, whichever is less. */ static unsigned ascii2desc(char const *s, u8 *utf, unsigned utfmax) { u8 * const utf0 = utf; unsigned slen = strlen(s); if (slen > 126) slen = 126; /* Limit so 2 + 2*slen <= 255 */ if (!utfmax--) goto end; *utf++ = 2 + 2*slen; /* Descriptor total length */ if (!utfmax--) goto end; *utf++ = 3; /* Descriptor type 3 (string) */ if (utfmax > 2*slen) utfmax = 2*slen; while (utfmax--) { *utf++ = *s++; if (!utfmax--) break; *utf++ = 0; } end: return (unsigned)(utf - utf0); } static unsigned rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) { char buf[100]; char const *s; // language ids switch (id) { case 0: /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ static char const langids[4] = {4, 3, 0x09, 0x04}; if (len > 4) len = 4; memcpy(data, langids, len); return len; case 1: /* Serial number */ s = hcd->self.bus_name; break; case 2: /* Product name */ s = hcd->product_desc; break; case 3: /* Manufacturer */ snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, init_utsname()->release, hcd->driver->description); s = buf; break; default: /* Can't happen; caller guarantees it */ return 0; } return ascii2desc(s, data, len); } That sure looks a lot cleaner to me... -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html