From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from cross.elm.relay.mailchannels.net (cross.elm.relay.mailchannels.net [23.83.212.46]) by sourceware.org (Postfix) with ESMTPS id AA49638582A3 for ; Thu, 15 Sep 2022 14:00:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AA49638582A3 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 2A35F8C20FE; Thu, 15 Sep 2022 14:00:17 +0000 (UTC) Received: from pdx1-sub0-mail-a307 (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 580748C285B; Thu, 15 Sep 2022 14:00:16 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1663250416; a=rsa-sha256; cv=none; b=tXkmKfiN3pQ95l8odhagvZFd15Z6NNKKxnM5bQD9+182FDJL2SL6+21FBMEDyjHIuSl4w+ bwgciZ60HOFCwB6fhfny6TYtYFPC/tJRwDy8dqhmoiiqAeizz9L0Z0+9+WO+W7w2/QFlBr FnClKrfPABudoIlBeMo0MqT/nCrUWG+4WkVGXhtTn5PzwOcH/1uaR6miF25TTBRICEMZqa eCqJwME8OeowoLpc04HEF0n43hrrDiUzkwkdg6z6ohVvmIv25T5VE8vzBGhC4sWzfOAjM8 AZKzQHZBCxvVFeLbYHol+cb68hmM2Z56wSXCTk7OVQhVGO/4YMaKhh9/qNjdsg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1663250416; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=TRxjtkPPceh/bQKFawbc6/lR75p2jkWY8fhHE/o/B3g=; b=IEHIm1FtkMb/zuF6Yhhemv9pSz9saW8smapv5CYFD7TpWGzPmzTUjW80V//E1+9HF4MbNG OscEdS4oHcwf673oGeJpwE1x+abWDPqm2M+3jIsp7XYBlQpuHbLdfOqDcCJesA/lJAR8Ss 2CN6XiGS9KYNIZMvK+av/0bFgaFj6UIU/twB58esAI2bm/Lp60QJnowZMz5UeCjcWX/fDT 0sgf+T5tn5G8wjLpUq4oXJJlRgz3a+sefbRsHKDX68Ys/E1+SMjMd+hGi7LaocSiovERXv 3Q5Ncxz9cLI//Pph6bPV1BmTF21nqs0LL/G1yyZuqgsNfUBrkIXcDixDalPMJQ== ARC-Authentication-Results: i=1; rspamd-f776c45b8-59n7m; auth=pass smtp.auth=dreamhost smtp.mailfrom=siddhesh@gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Glossy-Bored: 7c7b177418fb79a7_1663250416709_762519719 X-MC-Loop-Signature: 1663250416709:2383312243 X-MC-Ingress-Time: 1663250416709 Received: from pdx1-sub0-mail-a307 (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.111.194.74 (trex/6.7.1); Thu, 15 Sep 2022 14:00:16 +0000 Received: from [192.168.0.182] (bras-vprn-toroon4834w-lp130-16-184-147-84-238.dsl.bell.ca [184.147.84.238]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a307 (Postfix) with ESMTPSA id 4MSzNt2097zRW; Thu, 15 Sep 2022 07:00:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gotplt.org; s=dreamhost; t=1663250415; bh=TRxjtkPPceh/bQKFawbc6/lR75p2jkWY8fhHE/o/B3g=; h=Date:Subject:From:To:Cc:Content-Type:Content-Transfer-Encoding; b=vlq+rjLAckNLMhxJlj4B+ORQqN0/OxPMb3GnyG7r+72MuuKR4mhKsRuXUDE5u2PN0 IZnAlRxs+u9sOLyQJXV+Q8NvIztWKSt6D/NqSOdVsICeKoTxVcXR/TSdKdcUdZ0dkw nqM5aa7lg/HqCTEsQdg9fV9oArVTz3heJq3vmrm8TJ/FTWcd2ws1U1liyrkhbpPPh5 Yrw/vOMckUGLcEmw0MRigao99QK3HVBfkduZK1HQNYa7UwEi4WWcyFxRY7LpwGBdUp jizw2dhB1fdWWc37Oub0hnH27me/3J3CJwBzKN+1/iuTDIFQf8xUGa/Yfzdj54ETpo bH4inJ07pyEHQ== Message-ID: <722b2d59-4482-a29f-b2e9-99d9242fda31@gotplt.org> Date: Thu, 15 Sep 2022 10:00:11 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.12.0 Subject: Re: [PATCH] tree-object-size: Support strndup and strdup Content-Language: en-US From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Cc: jakub@redhat.com References: <20220815192311.763473-1-siddhesh@gotplt.org> <14f0d167-0f75-fba1-b326-071184737448@gotplt.org> <3544076e-05f4-a69a-95bc-cc48190db699@gotplt.org> In-Reply-To: <3544076e-05f4-a69a-95bc-cc48190db699@gotplt.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3037.4 required=5.0 tests=BAYES_00,BODY_8BITS,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,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: Ping! On 2022-09-07 15:21, Siddhesh Poyarekar wrote: > Ping! > > On 2022-08-29 10:16, Siddhesh Poyarekar wrote: >> Ping! >> >> On 2022-08-15 15:23, 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 (get_whole_object): New function. >>>     (addr_object_size): Use it. >>>     (strdup_object_size): New function. >>>     (call_object_size): Use it. >>>     (pass_data_object_sizes, pass_data_early_object_sizes): Set >>>     todo_flags_finish to TODO_update_ssa_no_phi. >>> >>> 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. >>> --- >>>   .../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  | 64 +++++++++++++++- >>>   gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++++++++++++++- >>>   gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++++++++++++++- >>>   gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++++++++++++++- >>>   gcc/tree-object-size.cc                       | 76 +++++++++++++++++-- >>>   10 files changed, 366 insertions(+), 14 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..7f023708b15 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) != 0) >>> +    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..4fbd372d97a 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,64 @@ 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) != 64) >>> +#endif >>> +    abort (); >>> + >>> +  free (res); >>> +  free (ptr2); >>> +} >>> + >>>   int >>>   main (void) >>>   { >>> @@ -644,5 +705,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..beb271c5afc 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,63 @@ 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) != 64) >>> +#endif >>> +    abort (); >>> + >>> +  free (res); >>> +  free (ptr2); >>> +} >>> + >>>   int >>>   main (void) >>>   { >>> @@ -557,5 +617,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..5c878a14647 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,63 @@ 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) != 0) >>> +    abort (); >>> + >>> +  free (res); >>> + >>> +  res = strndup (ptr2, 32); >>> +  if (__builtin_object_size (res, 2) != 0) >>> +    abort (); >>> + >>> +  free (res); >>> + >>> +  res = strndup (ptr2, 128); >>> +  if (__builtin_object_size (res, 2) != 0) >>> +    abort (); >>> + >>> +  free (res); >>> + >>> +  res = strdup (ptr2); >>> +#ifdef __builtin_object_size >>> +  if (__builtin_object_size (res, 2) != 27) >>> +#else >>> +  if (__builtin_object_size (res, 2) != 0) >>> +#endif >>> +    abort (); >>> + >>> +  free (res); >>> +  free (ptr2); >>> +} >>> + >>>   int >>>   main (void) >>>   { >>> @@ -651,5 +711,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..0b1cb1e528a 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,63 @@ 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) != 0) >>> +    abort (); >>> + >>> +  free (res); >>> + >>> +  res = strndup (ptr2, 32); >>> +  if (__builtin_object_size (res, 3) != 0) >>> +    abort (); >>> + >>> +  free (res); >>> + >>> +  res = strndup (ptr2, 128); >>> +  if (__builtin_object_size (res, 3) != 0) >>> +    abort (); >>> + >>> +  free (res); >>> + >>> +  res = strdup (ptr2); >>> +#ifdef __builtin_object_size >>> +  if (__builtin_object_size (res, 3) != 27) >>> +#else >>> +  if (__builtin_object_size (res, 3) != 0) >>> +#endif >>> +    abort (); >>> + >>> +  free (res); >>> +  free (ptr2); >>> +} >>> + >>>   int >>>   main (void) >>>   { >>> @@ -530,5 +590,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 4eb454a4a33..c075b71db56 100644 >>> --- a/gcc/tree-object-size.cc >>> +++ b/gcc/tree-object-size.cc >>> @@ -495,6 +495,18 @@ decl_init_size (tree decl, bool min) >>>     return size; >>>   } >>> +/* Get the outermost object that PTR may point into.  */ >>> + >>> +static tree >>> +get_whole_object (const_tree ptr) >>> +{ >>> +  tree pt_var = TREE_OPERAND (ptr, 0); >>> +  while (handled_component_p (pt_var)) >>> +    pt_var = TREE_OPERAND (pt_var, 0); >>> + >>> +  return pt_var; >>> +} >>> + >>>   /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR. >>>      OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. >>>      If unknown, return size_unknown (object_size_type).  */ >>> @@ -514,9 +526,7 @@ addr_object_size (struct object_size_info *osi, >>> const_tree ptr, >>>     if (pwholesize) >>>       *pwholesize = size_unknown (object_size_type); >>> -  pt_var = TREE_OPERAND (ptr, 0); >>> -  while (handled_component_p (pt_var)) >>> -    pt_var = TREE_OPERAND (pt_var, 0); >>> +  pt_var = get_whole_object (ptr); >>>     if (!pt_var) >>>       return false; >>> @@ -789,6 +799,53 @@ 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 = is_strndup ? gimple_call_arg (call, 1) : NULL_TREE; >>> + >>> +  /* For strdup, simply emit strlen (SRC) + 1 and let the optimizer >>> fold it the >>> +     way it likes.  */ >>> +  if (!is_strndup) >>> +    { >>> +      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)); >>> +    } >>> + >>> +  /* 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_whole_object (src); >>> + >>> +      if (!(object_size_type & OST_MINIMUM) >>> +      || (wholesrc && TREE_CODE (wholesrc) == STRING_CST)) >>> +    compute_builtin_object_size (src, object_size_type, &sz); >>> +    } >>> + >>> +  if (!n) >>> +    return sz; >>> + >>> +  /* Factor in the N.  Note that with OST_MINIMUM, even if N is >>> known we return >>> +     0 since the size could be less than N.  */ >>> +  return fold_build2 (MIN_EXPR, sizetype, >>> +              fold_build2 (PLUS_EXPR, sizetype, size_one_node, n), >>> +              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. >>> @@ -1235,12 +1292,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); >>> @@ -2113,7 +2177,7 @@ const pass_data pass_data_object_sizes = >>>     PROP_objsz, /* properties_provided */ >>>     0, /* properties_destroyed */ >>>     0, /* todo_flags_start */ >>> -  0, /* todo_flags_finish */ >>> +  TODO_update_ssa_no_phi, /* todo_flags_finish */ >>>   }; >>>   class pass_object_sizes : public gimple_opt_pass >>> @@ -2153,7 +2217,7 @@ const pass_data pass_data_early_object_sizes = >>>     0, /* properties_provided */ >>>     0, /* properties_destroyed */ >>>     0, /* todo_flags_start */ >>> -  0, /* todo_flags_finish */ >>> +  TODO_update_ssa_no_phi, /* todo_flags_finish */ >>>   }; >>>   class pass_early_object_sizes : public gimple_opt_pass >> >