From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-io1-xd31.google.com (mail-io1-xd31.google.com [IPv6:2607:f8b0:4864:20::d31]) by sourceware.org (Postfix) with ESMTPS id 6B8AC385841B for ; Fri, 4 Nov 2022 13:43:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 6B8AC385841B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org Received: by mail-io1-xd31.google.com with SMTP id p141so3788612iod.6 for ; Fri, 04 Nov 2022 06:43:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=Kav+0ue6VzHimwOliOCcuxy2wYm1HDg9RBSLCwEQdDQ=; b=SSE426NdmBJUpC6AnfeKN+iWFE9FO4MZmdh8ZtsWsNKVpFuCddieWMovSWF/gI/y7Z 9jmAP4FKBqFiillQ+A0XXbSZNcWpGvI94eD0pGrUijaFQpD1Kq7PzlpQluD1CDIA5mrN IU8kB2bUJ2GL2cfOpVT0uZ+r8pUptYd/CjUGqvMMffw7tKTfwy84OG/EDH9M0dkQ3P4S q+VxIEKSRmVYtMn3z0pBOxxQpaNHdWSFb63Zc0ks8aUsRTMURrTGIhz5SrYz6GjC4D7E GECAnX+FMX+7bClDxUjBQtGb+bejQmV1bevl5TsN9sj6Rr60GVHpFklxMrFhdwZGRT4N yE0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Kav+0ue6VzHimwOliOCcuxy2wYm1HDg9RBSLCwEQdDQ=; b=PTdCTSXBXlf4i5y+ehmm+pRWAN8wSDidIKYQ+o3BDzMr23OlC/9uyhfSvTBuVvW32Y ZvRsH9pDsSoNptF3/MzkULP7277oos6z34b2NU5XO6mGYxXhZo97js0gJEND8sBKK5x1 3rnu8N8Ks1fDPsD41+vXtME0j8q4Et6/OxRJyHnLPJ87m0AGGpGSv6N4ikN7iJBoHDhm 6KAl0ImreLAnHZE7bxuv3mjFek4iC1WK+57OEC933IpNBK5JIA3LTeFhnfjBfzoCtJHY mO/laWElQ2XarY+4DQu/Bs8Nc86KzOMEPXxo144+pKtMVmyr597C2pUuR5Q2ycTfypJ6 s0IA== X-Gm-Message-State: ACrzQf351rV2kFglxn1i5JWiNmsXitEj5pirmRONN0xoh/J42+KRyN81 H7CVuhM5lUj6Ran53by2uXpACKM/jCaqDLPPRHZYSxw+R/w= X-Google-Smtp-Source: AMsMyM5hlXjcU0VbQrnFB3MqjUPcP0O4clpy2ImDIAND7eFiX4voxSoEwSCSz/2wsQKvRpU17C75mkkdi39qsiWAb+0= X-Received: by 2002:a05:6602:14d4:b0:6d8:309b:bc4d with SMTP id b20-20020a05660214d400b006d8309bbc4dmr385423iow.26.1667569436317; Fri, 04 Nov 2022 06:43:56 -0700 (PDT) MIME-Version: 1.0 References: <20220815192311.763473-1-siddhesh@gotplt.org> <20221104124800.910588-1-siddhesh@gotplt.org> In-Reply-To: <20221104124800.910588-1-siddhesh@gotplt.org> From: Prathamesh Kulkarni Date: Fri, 4 Nov 2022 19:13:19 +0530 Message-ID: Subject: Re: [PATCH v2] tree-object-size: Support strndup and strdup To: Siddhesh Poyarekar Cc: gcc-patches@gcc.gnu.org, jakub@redhat.com Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.4 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Fri, 4 Nov 2022 at 18:18, Siddhesh Poyarekar wrote: > > Use string length of input to strdup to determine the usable size of the > resulting object. Avoid doing the same for strndup since there's a > chance that the input may be too large, resulting in an unnecessary > overhead or worse, the input may not be NULL terminated, resulting in a > crash where there would otherwise have been none. > > gcc/ChangeLog: > > * tree-object-size.cc (todo): New variable. > (object_sizes_execute): Use it. > (strdup_object_size): New function. > (call_object_size): Use it. > > gcc/testsuite/ChangeLog: > > * gcc.dg/builtin-dynamic-object-size-0.c (test_strdup, > test_strndup, test_strdup_min, test_strndup_min): New tests. > (main): Call them. > * gcc.dg/builtin-dynamic-object-size-1.c: Silence overread > warnings. > * gcc.dg/builtin-dynamic-object-size-2.c: Likewise. > * gcc.dg/builtin-dynamic-object-size-3.c: Likewise. > * gcc.dg/builtin-dynamic-object-size-4.c: Likewise. > * gcc.dg/builtin-object-size-1.c: Silence overread warnings. > Declare free, strdup and strndup. > (test11): New test. > (main): Call it. > * gcc.dg/builtin-object-size-2.c: Silence overread warnings. > Declare free, strdup and strndup. > (test9): New test. > (main): Call it. > * gcc.dg/builtin-object-size-3.c: Silence overread warnings. > Declare free, strdup and strndup. > (test11): New test. > (main): Call it. > * gcc.dg/builtin-object-size-4.c: Silence overread warnings. > Declare free, strdup and strndup. > (test9): New test. > (main): Call it. > --- > Tested: > > - x86_64 bootstrap and testsuite run > - i686 build and testsuite run > - ubsan bootstrap > > .../gcc.dg/builtin-dynamic-object-size-0.c | 43 +++++++++ > .../gcc.dg/builtin-dynamic-object-size-1.c | 2 +- > .../gcc.dg/builtin-dynamic-object-size-2.c | 2 +- > .../gcc.dg/builtin-dynamic-object-size-3.c | 2 +- > .../gcc.dg/builtin-dynamic-object-size-4.c | 2 +- > gcc/testsuite/gcc.dg/builtin-object-size-1.c | 94 +++++++++++++++++- > gcc/testsuite/gcc.dg/builtin-object-size-2.c | 94 +++++++++++++++++- > gcc/testsuite/gcc.dg/builtin-object-size-3.c | 95 ++++++++++++++++++- > gcc/testsuite/gcc.dg/builtin-object-size-4.c | 94 +++++++++++++++++- > gcc/tree-object-size.cc | 84 +++++++++++++++- > 10 files changed, 502 insertions(+), 10 deletions(-) > > diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c > index 01a280b2d7b..4f1606a486b 100644 > --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c > +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c > @@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, int incr) > return __builtin_dynamic_object_size (ptr, 0); > } > > +/* strdup/strndup. */ > + > +size_t > +__attribute__ ((noinline)) > +test_strdup (const char *in) > +{ > + char *res = __builtin_strdup (in); > + return __builtin_dynamic_object_size (res, 0); > +} > + > +size_t > +__attribute__ ((noinline)) > +test_strndup (const char *in, size_t bound) > +{ > + char *res = __builtin_strndup (in, bound); > + return __builtin_dynamic_object_size (res, 0); > +} > + > +size_t > +__attribute__ ((noinline)) > +test_strdup_min (const char *in) > +{ > + char *res = __builtin_strdup (in); > + return __builtin_dynamic_object_size (res, 2); > +} > + > +size_t > +__attribute__ ((noinline)) > +test_strndup_min (const char *in, size_t bound) > +{ > + char *res = __builtin_strndup (in, bound); > + return __builtin_dynamic_object_size (res, 2); > +} > + > /* Other tests. */ > > struct TV4 > @@ -651,6 +685,15 @@ main (int argc, char **argv) > int *t = test_pr105736 (&val3); > if (__builtin_dynamic_object_size (t, 0) != -1) > FAIL (); > + const char *str = "hello world"; > + if (test_strdup (str) != __builtin_strlen (str) + 1) > + FAIL (); > + if (test_strndup (str, 4) != 5) > + FAIL (); > + if (test_strdup_min (str) != __builtin_strlen (str) + 1) > + FAIL (); > + if (test_strndup_min (str, 4) != 1) > + FAIL (); > > if (nfails > 0) > __builtin_abort (); > diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c > index 7cc8b1c9488..8f17c8edcaf 100644 > --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c > +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > #define __builtin_object_size __builtin_dynamic_object_size > diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c > index 267dbf48ca7..3677782ff1c 100644 > --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c > +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > #define __builtin_object_size __builtin_dynamic_object_size > diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c > index fb9dc56da7e..5b6987b7773 100644 > --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c > +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > #define __builtin_object_size __builtin_dynamic_object_size > diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c > index 870548b4206..9d796224e96 100644 > --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c > +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > #define __builtin_object_size __builtin_dynamic_object_size > diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c > index b772e2da9b9..c6e5b4c29f8 100644 > --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c > +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > typedef __SIZE_TYPE__ size_t; > @@ -7,10 +7,13 @@ extern void abort (void); > extern void exit (int); > extern void *malloc (size_t); > extern void *calloc (size_t, size_t); > +extern void free (void *); > extern void *alloca (size_t); > extern void *memcpy (void *, const void *, size_t); > extern void *memset (void *, int, size_t); > extern char *strcpy (char *, const char *); > +extern char *strdup (const char *); > +extern char *strndup (const char *, size_t); > > struct A > { > @@ -629,6 +632,94 @@ test10 (void) > } > } > > +/* Tests for strdup/strndup. */ > +size_t > +__attribute__ ((noinline)) > +test11 (void) > +{ > + int i = 0; > + const char *ptr = "abcdefghijklmnopqrstuvwxyz"; > + char *res = strndup (ptr, 21); > + if (__builtin_object_size (res, 0) != 22) > + abort (); > + > + free (res); > + > + res = strndup (ptr, 32); > + if (__builtin_object_size (res, 0) != 27) > + abort (); > + > + free (res); > + > + res = strdup (ptr); > + if (__builtin_object_size (res, 0) != 27) > + abort (); > + > + free (res); > + > + char *ptr2 = malloc (64); > + strcpy (ptr2, ptr); > + > + res = strndup (ptr2, 21); > + if (__builtin_object_size (res, 0) != 22) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 32); > + if (__builtin_object_size (res, 0) != 33) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 128); > + if (__builtin_object_size (res, 0) != 64) > + abort (); > + > + free (res); > + > + res = strdup (ptr2); > +#ifdef __builtin_object_size > + if (__builtin_object_size (res, 0) != 27) > +#else > + if (__builtin_object_size (res, 0) != (size_t) -1) > +#endif > + abort (); > + free (res); > + free (ptr2); > + > + ptr = "abcd\0efghijklmnopqrstuvwxyz"; > + res = strdup (ptr); > + if (__builtin_object_size (res, 0) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 24); > + if (__builtin_object_size (res, 0) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 2); > + if (__builtin_object_size (res, 0) != 3) > + abort (); > + free (res); > + > + res = strdup (&ptr[4]); > + if (__builtin_object_size (res, 0) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 4); > + if (__builtin_object_size (res, 0) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 1); > + if (__builtin_object_size (res, 0) != 1) > + abort (); > + free (res); > +} > + > int > main (void) > { > @@ -644,5 +735,6 @@ main (void) > test8 (); > test9 (1); > test10 (); > + test11 (); > exit (0); > } > diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c > index 2729538da17..639a83cfd39 100644 > --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c > +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > typedef __SIZE_TYPE__ size_t; > @@ -7,10 +7,13 @@ extern void abort (void); > extern void exit (int); > extern void *malloc (size_t); > extern void *calloc (size_t, size_t); > +extern void free (void *); > extern void *alloca (size_t); > extern void *memcpy (void *, const void *, size_t); > extern void *memset (void *, int, size_t); > extern char *strcpy (char *, const char *); > +extern char *strdup (const char *); > +extern char *strndup (const char *, size_t); > > struct A > { > @@ -544,6 +547,94 @@ test8 (unsigned cond) > #endif > } > > +/* Tests for strdup/strndup. */ > +size_t > +__attribute__ ((noinline)) > +test9 (void) > +{ > + const char *ptr = "abcdefghijklmnopqrstuvwxyz"; > + char *res = strndup (ptr, 21); > + if (__builtin_object_size (res, 1) != 22) > + abort (); > + > + free (res); > + > + res = strndup (ptr, 32); > + if (__builtin_object_size (res, 1) != 27) > + abort (); > + > + free (res); > + > + res = strdup (ptr); > + if (__builtin_object_size (res, 1) != 27) > + abort (); > + > + free (res); > + > + char *ptr2 = malloc (64); > + strcpy (ptr2, ptr); > + > + res = strndup (ptr2, 21); > + if (__builtin_object_size (res, 1) != 22) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 32); > + if (__builtin_object_size (res, 1) != 33) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 128); > + if (__builtin_object_size (res, 1) != 64) > + abort (); > + > + free (res); > + > + res = strdup (ptr2); > +#ifdef __builtin_object_size > + if (__builtin_object_size (res, 1) != 27) > +#else > + if (__builtin_object_size (res, 1) != (size_t) -1) > +#endif > + abort (); > + > + free (res); > + free (ptr2); > + > + ptr = "abcd\0efghijklmnopqrstuvwxyz"; > + res = strdup (ptr); > + if (__builtin_object_size (res, 1) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 24); > + if (__builtin_object_size (res, 1) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 2); > + if (__builtin_object_size (res, 1) != 3) > + abort (); > + free (res); > + > + res = strdup (&ptr[4]); > + if (__builtin_object_size (res, 1) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 4); > + if (__builtin_object_size (res, 1) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 1); > + if (__builtin_object_size (res, 1) != 1) > + abort (); > + free (res); > +} > + > int > main (void) > { > @@ -557,5 +648,6 @@ main (void) > test6 (); > test7 (); > test8 (1); > + test9 (); > exit (0); > } > diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c > index 44a99189776..ff4f1747334 100644 > --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c > +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > typedef __SIZE_TYPE__ size_t; > @@ -7,10 +7,13 @@ extern void abort (void); > extern void exit (int); > extern void *malloc (size_t); > extern void *calloc (size_t, size_t); > +extern void free (void *); > extern void *alloca (size_t); > extern void *memcpy (void *, const void *, size_t); > extern void *memset (void *, int, size_t); > extern char *strcpy (char *, const char *); > +extern char *strdup (const char *); > +extern char *strndup (const char *, size_t); > > struct A > { > @@ -636,6 +639,95 @@ test10 (void) > } > } > > +/* Tests for strdup/strndup. */ > +size_t > +__attribute__ ((noinline)) > +test11 (void) > +{ > + const char *ptr = "abcdefghijklmnopqrstuvwxyz"; > + char *res = strndup (ptr, 21); > + if (__builtin_object_size (res, 2) != 22) > + abort (); > + > + free (res); > + > + res = strndup (ptr, 32); > + if (__builtin_object_size (res, 2) != 27) > + abort (); > + > + free (res); > + > + res = strdup (ptr); > + if (__builtin_object_size (res, 2) != 27) > + abort (); > + > + free (res); > + > + char *ptr2 = malloc (64); > + strcpy (ptr2, ptr); > + > + res = strndup (ptr2, 21); > + if (__builtin_object_size (res, 2) != 1) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 32); > + if (__builtin_object_size (res, 2) != 1) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 128); > + if (__builtin_object_size (res, 2) != 1) > + abort (); > + > + free (res); > + > + res = strdup (ptr2); > + > +#ifdef __builtin_object_size > + if (__builtin_object_size (res, 2) != 27) > +#else > + if (__builtin_object_size (res, 2) != 1) > +#endif > + abort (); > + > + free (res); > + free (ptr2); > + > + ptr = "abcd\0efghijklmnopqrstuvwxyz"; > + res = strdup (ptr); > + if (__builtin_object_size (res, 2) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 24); > + if (__builtin_object_size (res, 2) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 2); > + if (__builtin_object_size (res, 2) != 3) > + abort (); > + free (res); > + > + res = strdup (&ptr[4]); > + if (__builtin_object_size (res, 2) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 4); > + if (__builtin_object_size (res, 2) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 1); > + if (__builtin_object_size (res, 2) != 1) > + abort (); > + free (res); > +} > + > int > main (void) > { > @@ -651,5 +743,6 @@ main (void) > test8 (); > test9 (1); > test10 (); > + test11 (); > exit (0); > } > diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c > index b9fddfed036..4c007c364b7 100644 > --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c > +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c > @@ -1,5 +1,5 @@ > /* { dg-do run } */ > -/* { dg-options "-O2" } */ > +/* { dg-options "-O2 -Wno-stringop-overread" } */ > /* { dg-require-effective-target alloca } */ > > typedef __SIZE_TYPE__ size_t; > @@ -7,10 +7,13 @@ extern void abort (void); > extern void exit (int); > extern void *malloc (size_t); > extern void *calloc (size_t, size_t); > +extern void free (void *); > extern void *alloca (size_t); > extern void *memcpy (void *, const void *, size_t); > extern void *memset (void *, int, size_t); > extern char *strcpy (char *, const char *); > +extern char *strdup (const char *); > +extern char *strndup (const char *, size_t); > > struct A > { > @@ -517,6 +520,94 @@ test8 (unsigned cond) > #endif > } > > +/* Tests for strdup/strndup. */ > +size_t > +__attribute__ ((noinline)) > +test9 (void) > +{ > + const char *ptr = "abcdefghijklmnopqrstuvwxyz"; > + char *res = strndup (ptr, 21); > + if (__builtin_object_size (res, 3) != 22) > + abort (); > + > + free (res); > + > + res = strndup (ptr, 32); > + if (__builtin_object_size (res, 3) != 27) > + abort (); > + > + free (res); > + > + res = strdup (ptr); > + if (__builtin_object_size (res, 3) != 27) > + abort (); > + > + free (res); > + > + char *ptr2 = malloc (64); > + strcpy (ptr2, ptr); > + > + res = strndup (ptr2, 21); > + if (__builtin_object_size (res, 3) != 1) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 32); > + if (__builtin_object_size (res, 3) != 1) > + abort (); > + > + free (res); > + > + res = strndup (ptr2, 128); > + if (__builtin_object_size (res, 3) != 1) > + abort (); > + > + free (res); > + > + res = strdup (ptr2); > +#ifdef __builtin_object_size > + if (__builtin_object_size (res, 3) != 27) > +#else > + if (__builtin_object_size (res, 3) != 1) > +#endif > + abort (); > + > + free (res); > + free (ptr2); > + > + ptr = "abcd\0efghijklmnopqrstuvwxyz"; > + res = strdup (ptr); > + if (__builtin_object_size (res, 3) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 24); > + if (__builtin_object_size (res, 3) != 5) > + abort (); > + free (res); > + > + res = strndup (ptr, 2); > + if (__builtin_object_size (res, 3) != 3) > + abort (); > + free (res); > + > + res = strdup (&ptr[4]); > + if (__builtin_object_size (res, 3) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 4); > + if (__builtin_object_size (res, 3) != 1) > + abort (); > + free (res); > + > + res = strndup (&ptr[4], 1); > + if (__builtin_object_size (res, 3) != 1) > + abort (); > + free (res); > +} > + > int > main (void) > { > @@ -530,5 +621,6 @@ main (void) > test6 (); > test7 (); > test8 (1); > + test9 (); > exit (0); > } > diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc > index 1f04cb80fd0..08e5731617d 100644 > --- a/gcc/tree-object-size.cc > +++ b/gcc/tree-object-size.cc > @@ -89,6 +89,10 @@ static bitmap computed[OST_END]; > /* Maximum value of offset we consider to be addition. */ > static unsigned HOST_WIDE_INT offset_limit; > > +/* Tell the generic SSA updater what kind of update is needed after the pass > + executes. */ > +static unsigned todo; > + > /* Return true if VAL represents an initial size for OBJECT_SIZE_TYPE. */ > > static inline bool > @@ -787,6 +791,73 @@ alloc_object_size (const gcall *call, int object_size_type) > return bytes ? bytes : size_unknown (object_size_type); > } > > +/* Compute __builtin_object_size for CALL, which is a call to either > + BUILT_IN_STRDUP or BUILT_IN_STRNDUP; IS_STRNDUP indicates which it is. > + OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. > + If unknown, return size_unknown (object_size_type). */ > + > +static tree > +strdup_object_size (const gcall *call, int object_size_type, bool is_strndup) > +{ > + tree src = gimple_call_arg (call, 0); > + tree sz = size_unknown (object_size_type); > + tree n = NULL_TREE; > + > + if (is_strndup) > + n = fold_build2 (PLUS_EXPR, sizetype, size_one_node, > + gimple_call_arg (call, 1)); > + > + > + /* For strdup, simply emit strlen (SRC) + 1 and let the optimizer fold it the > + way it likes. */ > + if (!is_strndup) Sorry to nitpick, should this just be under else ? Since this condition will be false if the above if (is_strndup) is true. Thanks, Prathamesh > + { > + tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN); > + if (strlen_fn) > + { > + sz = fold_build2 (PLUS_EXPR, sizetype, size_one_node, > + build_call_expr (strlen_fn, 1, src)); > + todo = TODO_update_ssa_only_virtuals; > + } > + } > + > + /* In all other cases, return the size of SRC since the object size cannot > + exceed that. We cannot do this for OST_MINIMUM unless SRC points into a > + string constant since otherwise the object size could go all the way down > + to zero. */ > + if (!size_valid_p (sz, object_size_type) > + || size_unknown_p (sz, object_size_type)) > + { > + tree wholesrc = NULL_TREE; > + if (TREE_CODE (src) == ADDR_EXPR) > + wholesrc = get_base_address (TREE_OPERAND (src, 0)); > + > + /* If the source points within a string constant, we try to get its > + length. */ > + if (wholesrc && TREE_CODE (wholesrc) == STRING_CST) > + { > + tree len = c_strlen (src, 0); > + if (len) > + sz = fold_build2 (PLUS_EXPR, sizetype, size_one_node, len); > + } > + > + /* For maximum estimate, our next best guess is the object size of the > + source. */ > + if (size_unknown_p (sz, object_size_type) > + && !(object_size_type & OST_MINIMUM)) > + compute_builtin_object_size (src, object_size_type, &sz); > + } > + > + /* String duplication allocates at least one byte, so we should never fail > + for OST_MINIMUM. */ > + if ((!size_valid_p (sz, object_size_type) > + || size_unknown_p (sz, object_size_type)) > + && (object_size_type & OST_MINIMUM)) > + sz = size_one_node; > + > + /* Factor in the N. */ > + return n ? fold_build2 (MIN_EXPR, sizetype, n, sz) : sz; > +} > > /* If object size is propagated from one of function's arguments directly > to its return value, return that argument for GIMPLE_CALL statement CALL. > @@ -1233,12 +1304,19 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) > { > int object_size_type = osi->object_size_type; > unsigned int varno = SSA_NAME_VERSION (ptr); > + tree bytes = NULL_TREE; > > gcc_assert (is_gimple_call (call)); > > gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); > gcc_assert (osi->pass == 0); > - tree bytes = alloc_object_size (call, object_size_type); > + > + bool is_strdup = gimple_call_builtin_p (call, BUILT_IN_STRDUP); > + bool is_strndup = gimple_call_builtin_p (call, BUILT_IN_STRNDUP); > + if (is_strdup || is_strndup) > + bytes = strdup_object_size (call, object_size_type, is_strndup); > + else > + bytes = alloc_object_size (call, object_size_type); > > if (!size_valid_p (bytes, object_size_type)) > bytes = size_unknown (object_size_type); > @@ -1998,6 +2076,8 @@ dynamic_object_sizes_execute_one (gimple_stmt_iterator *i, gimple *call) > static unsigned int > object_sizes_execute (function *fun, bool early) > { > + todo = 0; > + > basic_block bb; > FOR_EACH_BB_FN (bb, fun) > { > @@ -2094,7 +2174,7 @@ object_sizes_execute (function *fun, bool early) > } > > fini_object_sizes (); > - return 0; > + return todo; > } > > /* Simple pass to optimize all __builtin_object_size () builtins. */ > -- > 2.37.3 >