From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 108768 invoked by alias); 25 Feb 2020 12:48:57 -0000 Mailing-List: contact libc-help-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Post: List-Help: , Sender: libc-help-owner@sourceware.org Received: (qmail 108724 invoked by uid 89); 25 Feb 2020 12:48:53 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-1.6 required=5.0 tests=AWL,BAYES_00,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.1 spammy=mardi, lengths, H*i:sk:87h7zfh, H*f:sk:87h7zfh X-HELO: galex-713.eu Received: from portable.galex-713.eu (HELO galex-713.eu) (89.234.186.82) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 25 Feb 2020 12:48:52 +0000 Received: from gal by galex-713.eu with local (Exim 4.92) (envelope-from ) id 1j6ZdZ-0005yH-Kd; Tue, 25 Feb 2020 13:48:33 +0100 From: Alexandre =?ISO-8859-1?Q?Fran=E7ois?= Garreau To: Florian Weimer Cc: libc-help@sourceware.org Subject: Re: =?UTF-8?B?bWFsbG9j4oCZaW5n?= strcat Date: Tue, 25 Feb 2020 12:48:00 -0000 Message-ID: <8697722.BVzDMqqv4M@galex-713.eu> In-Reply-To: <87h7zfhulx.fsf@oldenburg2.str.redhat.com> References: <25950016.Ncol2qhMyO@galex-713.eu> <1920232.nxOQ8X6Npi@galex-713.eu> <87h7zfhulx.fsf@oldenburg2.str.redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="UTF-8" X-IsSubscribed: yes X-SW-Source: 2020-02/txt/msg00050.txt.bz2 Le mardi 25 f=C3=A9vrier 2020, 10:41:30 CET Florian Weimer a =C3=A9crit : > * Alexandre Fran=C3=A7ois Garreau: > >> I think I wouldn't use the NULL sentinel for the reasons indicated > >> (silent truncation after memory allocation or other failure, even > >> under > >> valgrind), and use > >>=20 > >> sizeof ((const char *[]) { __VA_ARGS__ }) / sizeof (const char *) > >>=20 > >> to compute the number of arguments, and pass that separately from the > >> pointer. > >=20 > > you mean like that? > > #define anstrcat(...) \ > > astrncat(sizeof((char *[]) {__VA_ARGS__}), \ > >=20 > > (char *[]) {__VA_ARGS__}) > >=20 > > char * anstrcat (size_t n; char *strarray[]) > > { > >=20 > > char * result =3D malloc(1); > > size_t len =3D 1; > > result[0] =3D '\0'; > > for (off_t i =3D 0; i < n; ++i) > > result =3D strcat(realloc(result, len +=3D strlen(strarray[i])), > >=20 > > strarray[i]); > >=20 > > return result; > >=20 > > } >=20 > Sort of, except with overflow checking I=E2=80=99m curious: how would it overflow if strlen already checks the end= (the=20 \0) of each string (so that it knows how much strcat will copy)? > and without the quadratic > behavior. Why is it quadratic? with a single loop=E2=80=A6 are you talking about call= ing=20 several times realloc, or strlen? Or simply about using strcpy or stpcpy (or memcpy or mempcpy so not to=20 check for \0-position a second time) instead because you could get the=20 NULL-char*position and hence the end of a string only once? char * anstrcat (size_t n; char *strarray[]) { char *result =3D NULL, *pos =3D result; size_t total_len =3D 1; for (off_t i =3D 0; i < n; ++i) { size_t len =3D strlen (strarray[i]); result =3D realloc (result, total_len +=3D len); pos =3D mempcpy (pos, strarray[i], len); } result[total_len-1] =3D '\0'; return result; } I don=E2=80=99t see how to do less than n strlen (except by asking to provi= de an=20 array of lengths but to me it=E2=80=99s overkill and not really C-ish to me= =E2=80=A6 we=20 need each string=E2=80=99s size=E2=80=A6) , nor how to call malloc only onc= e without first=20 doing twice as much strlens=E2=80=A6 except by storing them in an VLA array= (or=20 mallocated, for compatibility sake) but isn=E2=80=99t also that overkill? w= ell,=20 =E2=80=9Cmemory=E2=80=99s almost free=E2=80=9D=E2=80=A6 Is calling realloc = n times a bad thing? > > Yet this only works with a macro, and is it really unreasonable to > > expect not to give NULL args? >=20 > I think so. For the sake of not doing every single time the same malloc=E2=80=99s onese= lf, I=20 believe a such function would be too useful for a such requirement to=20 hinder its benefits=E2=80=A6 Also I like simple interfaces, and an interface that doesn=E2=80=99t requir= e to=20 count the arguments (the same way you don=E2=80=99t have to always provide = the=20 size of a string) looks cool to me=E2=80=A6 because I wonder about the case= s=20 people will have to use it without the macro=E2=80=A6=20 I mean such usage looks so basic and likely what everybody would do since=20 for much time that it ought to get a general interface so to factorize a=20 lot=E2=80=A6 > But there is another complication: The NULL sentinel is not portable > because NULL can be defined as 0, which does not have the correct type > for use in an argument list of character pointers. And would (char*)NULL work as a replacement? otherwise how one is to=20 specify a null pointer, a null object, etc. in a portable manner?