realloc

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Flash Gordon

    #16
    Re: realloc

    pete wrote:[color=blue]
    > Flash Gordon wrote:
    >
    >[color=green]
    >> /* improve chances of the fputs not running out of memory */[/color]
    >
    >
    > #include <stdio.h>
    >
    > int fput_s(const char *s, FILE *stream);
    >
    > int main(void)
    > {
    > fput_s(
    > "What kind of memory usage "
    > "are you envisioning for fputs?\n",
    > stdout
    > );
    > return 0;
    > }[/color]

    I don't care, but it might either allocate or increase the size of a
    buffer. I've recently been working with a DB wrapper layer that does
    clever things which can lead to you running out of resources trying to
    close a table because you have run out of resources, unless you first
    close all temporary tables. So strange things can happen on running out
    of resources, and that free was a cheap and easy way to reduce the
    chances of something strange happening.

    It was also a subtle hint to the OP that it was still allocated in case
    later s/he wants to do something more intelligent on on a realloc failure.

    Also, I'm happy if that is the worst thing anyone here comments on with
    a piece of my code.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.

    Comment

    • CBFalconer

      #17
      Re: realloc

      Roy wrote:[color=blue]
      >
      > Hi all :
      > My code below :
      >
      > #include <stdio.h>
      > #include <string.h>
      > #include <stdlib.h>
      >
      > char *cat(char *s, const char *t)
      > {
      > char *tmp;
      >
      > if (s == NULL)
      > tmp = realloc(s,strle n(t) + 1);
      > else
      > tmp = realloc(s,strle n(s) + strlen(t) + 1);
      > if (tmp == NULL) {
      > fputs("realloc error",stderr);
      > exit(1);
      > }
      > while (*tmp++); // search for '\0' and stop
      > tmp--; //the position of '\0'
      > while (*tmp++ = *t++) ;
      > s = tmp;
      > return s;
      > }
      >
      > int main()
      > {
      > char *tmp;
      > char *s;
      >
      > s = NULL;
      > tmp = cat(s,"oh");
      > printf("%s\n",t mp);
      > tmp = cat(s,"haha");
      > printf("%s\n",t mp);
      > return 0;
      > }
      > my problem is when I run the program the reslut is some blanks. I just
      > wrote a small routine like strcat and check the realloc and tmp pointer
      > carefully but found nothing.[/color]

      Here is a revision that appears to work. Notice the differences,
      including the use of blanks in the statements.

      #include <stdio.h>
      #include <string.h>
      #include <stdlib.h>

      char *cat(char *s, const char *t)
      {
      char *tmp;

      if (s == NULL) {
      tmp = realloc(s, strlen(t) + 1);
      if (tmp) *tmp = '\0';
      }
      else
      tmp = realloc(s, strlen(s) + strlen(t) + 1);
      if (tmp == NULL) {
      fputs("realloc error", stderr);
      exit(1);
      }
      else {
      s = tmp;
      while (*tmp++) continue; /* search for '\0' and stop */
      tmp--; /* the position of '\0' */
      while (*tmp++ = *t++) continue;
      }
      return s;
      }

      int main(void)
      {
      char *s;

      s = NULL;
      s = cat(s, "oh");
      printf("%s\n", s);
      s = cat(s, "haha");
      printf("%s\n", s);
      return 0;
      }


      --
      Some informative links:
      news:news.annou nce.newusers
      Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!






      Comment

      • Michael Knaup

        #18
        Re: realloc

        Al Bowers wrote:
        [color=blue]
        > char *cat(char **s1, const char *s2)
        > {
        > char *ret = NULL;
        >
        > if(s2)
        > {
        > char *tmp;
        > size_t sz1 = (!s1||!*s1)?0:s trlen(*s1);
        > size_t sz2 = strlen(s2);
        > if((tmp = realloc(s1?*s1: NULL,sz1+sz2+1) ) != NULL)
        > {[/color]
        I think we have undefined behavior in the case of "self-concatenation"
        (cat(&s, s);) so we should check for this case.[color=blue]
        > memcpy(tmp+sz1, s2,sz2+1);
        > ret = (s1)?*s1 = tmp:tmp;
        > }
        > }
        > return ret;
        > }
        >[/color]

        char* StrConcat (char ** pS0, const char * const s1)
        {
        char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));

        if (s1) {
        register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
        register size_t l1 = 1u + strlen (s1);
        if ((pTmp = realloc (pTmp, l0 + l1))) {
        if (*pS0 == s1) {
        memcpy (pTmp + l0, pTmp, l0);
        pTmp[l0 << 1] = '\000';
        } else {
        memcpy (pTmp + l0, s1, l1);
        }
        *pS0 = pTmp;
        }

        }

        return pTmp;
        }
        #define StrAlloc(s1) StrConcat(NULL, (s1))
        #define StrFree(s1) (free(s1), (s1) = NULL)

        --
        Michael Knaup

        Comment

        • Al Bowers

          #19
          Re: realloc



          Michael Knaup wrote:[color=blue]
          > Al Bowers wrote:
          >
          >[color=green]
          >>char *cat(char **s1, const char *s2)
          >>{
          >> char *ret = NULL;
          >>
          >> if(s2)
          >> {
          >> char *tmp;
          >> size_t sz1 = (!s1||!*s1)?0:s trlen(*s1);
          >> size_t sz2 = strlen(s2);
          >> if((tmp = realloc(s1?*s1: NULL,sz1+sz2+1) ) != NULL)
          >> {[/color]
          >
          > I think we have undefined behavior in the case of "self-concatenation"
          > (cat(&s, s);) so we should check for this case.[/color]

          I assume you are referring to the overlap hazard involving function
          memcpy. If one is to write the function cat to protect against the
          overlapUB, you should do more than check for the case of
          "self-concatenation". You should prevent all possible cases of
          overlap UB, ie. (cat(&s,s+1);) where strlen of s is greater than 1.
          [color=blue]
          >[color=green]
          >> memcpy(tmp+sz1, s2,sz2+1);[/color][/color]
          memmove(tmp+sz1 ,s2,sz2+1);

          Standard C provides function memmove which is similiar to memcpy
          but eliminates the overlap problem.
          [color=blue][color=green]
          >> ret = (s1)?*s1 = tmp:tmp;
          >> }
          >> }
          >> return ret;
          >>}
          >>[/color]
          >
          >
          > char* StrConcat (char ** pS0, const char * const s1)
          > {
          > char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
          >
          > if (s1) {
          > register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
          > register size_t l1 = 1u + strlen (s1);
          > if ((pTmp = realloc (pTmp, l0 + l1))) {
          > if (*pS0 == s1) {
          > memcpy (pTmp + l0, pTmp, l0);
          > pTmp[l0 << 1] = '\000';
          > } else {
          > memcpy (pTmp + l0, s1, l1);
          > }[/color]

          This if-else statement only catches the overlap UB then
          *pS0 == s1. Cases of overlap UB where *ps0 != s1 will
          make the StrCancat function subject to failure.
          [color=blue]
          > *pS0 = pTmp;
          > }
          >
          > }
          >
          > return pTmp;
          > }[/color]


          --
          Al Bowers
          Tampa, Fl USA
          mailto: xabowers@myrapi dsys.com (remove the x to send email)
          Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!


          Comment

          • Michael Knaup

            #20
            Re: realloc

            Al Bowers wrote:
            [color=blue]
            >
            >
            > Michael Knaup wrote:[color=green]
            >> Al Bowers wrote:
            >>
            >>[color=darkred]
            >>>char *cat(char **s1, const char *s2)
            >>>{
            >>> char *ret = NULL;
            >>>
            >>> if(s2)
            >>> {
            >>> char *tmp;
            >>> size_t sz1 = (!s1||!*s1)?0:s trlen(*s1);
            >>> size_t sz2 = strlen(s2);
            >>> if((tmp = realloc(s1?*s1: NULL,sz1+sz2+1) ) != NULL)
            >>> {[/color]
            >>
            >> I think we have undefined behavior in the case of "self-concatenation"
            >> (cat(&s, s);) so we should check for this case.[/color]
            >
            > I assume you are referring to the overlap hazard involving function
            > memcpy. If one is to write the function cat to protect against the
            > overlapUB, you should do more than check for the case of
            > "self-concatenation". You should prevent all possible cases of
            > overlap UB, ie. (cat(&s,s+1);) where strlen of s is greater than 1.[/color]

            No, not really, the pointer to s2 may become invalid by the realloc call if
            s2 == s1 and s1 != realloc(s1, new_size).

            In C99 you also may solve the problem by declaring s2 as
            const char * restrict s2 or
            const char *const restrict
            then self-concatenation is disallowed
            [color=blue]
            >[color=green]
            >>[color=darkred]
            >>> memcpy(tmp+sz1, s2,sz2+1);[/color][/color]
            > memmove(tmp+sz1 ,s2,sz2+1);
            >
            > Standard C provides function memmove which is similiar to memcpy
            > but eliminates the overlap problem.
            >[/color]
            As I wrote memmove will not solve the problem and no you have not to use
            memmove in the case of partial "self-concatenation". Because the only byte
            which would be a problem is the terminating '\000' of s1 and then it is
            enougth to handle string termination separatley. But again s2 may be
            invalid and you have to handle this.
            [color=blue][color=green][color=darkred]
            >>> ret = (s1)?*s1 = tmp:tmp;
            >>> }
            >>> }
            >>> return ret;
            >>>}
            >>>[/color]
            >>
            >>
            >> char* StrConcat (char ** pS0, const char * const s1)
            >> {
            >> char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
            >>
            >> if (s1) {
            >> register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
            >> register size_t l1 = 1u + strlen (s1);[/color][/color]
            ptrdiff_t d0 = s1 - *pS0;

            if ((pTmp = realloc (pTmp, l0 + l1))) {
            if (0 <= d0 && (size_t)d0 <= l0) {
            --l1;
            memcpy (pTmp + l0, pTmp + d0, l1);
            pTmp[l0 + l1] = '\000';
            [color=blue][color=green]
            >> } else {
            >> memcpy (pTmp + l0, s1, l1);
            >> }[/color]
            >[/color]

            I think, this will solve the failure for partial "self-concatenation"
            [color=blue]
            >[color=green]
            >> *pS0 = pTmp;
            >> }
            >>
            >> }
            >>
            >> return pTmp;
            >> }[/color]
            >
            >[/color]

            --
            Michael Knaup

            Comment

            • Al Bowers

              #21
              Re: realloc



              Michael Knaup wrote:[color=blue]
              > Al Bowers wrote:
              >
              >[color=green]
              >>
              >>Michael Knaup wrote:
              >>[color=darkred]
              >>>Al Bowers wrote:
              >>>
              >>>
              >>>
              >>>>char *cat(char **s1, const char *s2)
              >>>>{
              >>>> char *ret = NULL;
              >>>>
              >>>> if(s2)
              >>>> {
              >>>> char *tmp;
              >>>> size_t sz1 = (!s1||!*s1)?0:s trlen(*s1);
              >>>> size_t sz2 = strlen(s2);
              >>>> if((tmp = realloc(s1?*s1: NULL,sz1+sz2+1) ) != NULL)
              >>>> {
              >>>
              >>>I think we have undefined behavior in the case of "self-concatenation"
              >>>(cat(&s, s);) so we should check for this case.[/color]
              >>
              >>I assume you are referring to the overlap hazard involving function
              >>memcpy. If one is to write the function cat to protect against the
              >>overlapUB, you should do more than check for the case of
              >>"self-concatenation". You should prevent all possible cases of
              >>overlap UB, ie. (cat(&s,s+1);) where strlen of s is greater than 1.[/color]
              >
              >
              > No, not really, the pointer to s2 may become invalid by the realloc call if
              > s2 == s1 and s1 != realloc(s1, new_size).[/color]

              I see. Function realloc may possibly move the allocated space
              thus making s2 becoming invalid in cases of "self-concatenation"
              or partial "self-concatenation".
              [color=blue][color=green][color=darkred]
              >>>> memcpy(tmp+sz1, s2,sz2+1);[/color]
              >>
              >>memmove(tmp+s z1,s2,sz2+1);
              >>
              >>Standard C provides function memmove which is similiar to memcpy
              >>but eliminates the overlap problem.
              >>[color=darkred]
              >>>> ret = (s1)?*s1 = tmp:tmp;
              >>>> }
              >>>> }
              >>>> return ret;
              >>>>}
              >>>>
              >>>
              >>>
              >>>char* StrConcat (char ** pS0, const char * const s1)
              >>>{
              >>> char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
              >>>
              >>> if (s1) {
              >>> register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
              >>> register size_t l1 = 1u + strlen (s1);[/color][/color]
              >
              > ptrdiff_t d0 = s1 - *pS0;
              >
              > if ((pTmp = realloc (pTmp, l0 + l1))) {
              > if (0 <= d0 && (size_t)d0 <= l0) {
              > --l1;
              > memcpy (pTmp + l0, pTmp + d0, l1);
              > pTmp[l0 + l1] = '\000';
              >
              >[color=green][color=darkred]
              >>> } else {
              >>> memcpy (pTmp + l0, s1, l1);
              >>> }[/color]
              >>[/color]
              >
              > I think, this will solve the failure for partial "self-concatenation"[/color]

              But the function will still exhibit UB with the statement:
              ptrdiff_t d0 = s1 - *pS0;
              for d0 to be valid, both pointers need to point to elements
              of the same array object or one element just past the array
              object. This would be the case only for
              "self-concatenation" and partial "self-concatenation".
              The cases in which *pS0 and s1 are not both pointing to
              elements of the same array object, as described above,
              will make the use of d0 UB.
              [color=blue]
              >[color=green][color=darkred]
              >>> *pS0 = pTmp;
              >>> }
              >>>
              >>> }
              >>>
              >>> return pTmp;
              >>>}[/color]
              >>
              >>[/color]
              >[/color]

              --
              Al Bowers
              Tampa, Fl USA
              mailto: xabowers@myrapi dsys.com (remove the x to send email)
              Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!


              Comment

              • CBFalconer

                #22
                Re: realloc

                Al Bowers wrote:[color=blue]
                >[/color]
                .... snip ...[color=blue]
                >
                > I assume you are referring to the overlap hazard involving function
                > memcpy. If one is to write the function cat to protect against the
                > overlapUB, you should do more than check for the case of
                > "self-concatenation". You should prevent all possible cases of
                > overlap UB, ie. (cat(&s,s+1);) where strlen of s is greater than 1.[/color]

                In strlcpy/strlcat as commonly defined:

                size_t strlcpy(char *dst, const char *src, size_t sz);
                size_t strlcat(char *dst, const char *src, size_t sz);

                the use of sz will normally allow protection against such an
                anomaly as issuing:

                res = strlcat(dst, strchr(dst, 'X'), maxcapacity);

                (which is another justification for my treating NULL as an empty
                src string in my implementation of those functions, found at:
                <http://cbfalconer.home .att.net/download/>

                However, in general would the restrict qualifier afford
                protection? I am envisioning something like:

                char *s2, s1[SIZE] = "some nonsense";

                s2 = strchr(s1, 'n');
                ... obscurative code ...
                if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)

                where cat is the unprotected against length:

                char *cat(restrict char *dst, const char *src);

                and an inner loop of the form

                while (*dst++ = *src++) continue;

                will have a few problems terminating. Again, does restrict avoid
                this call? Should it? Or should it simply mean "don't do that".

                --
                "If you want to post a followup via groups.google.c om, don't use
                the broken "Reply" link at the bottom of the article. Click on
                "show options" at the top of the article, then click on the
                "Reply" at the bottom of the article headers." - Keith Thompson


                Comment

                • Michael Knaup

                  #23
                  Re: realloc

                  However, in general would the restrict qualifier afford[color=blue]
                  > protection? I am envisioning something like:
                  >
                  > char *s2, s1[SIZE] = "some nonsense";
                  >
                  > s2 = strchr(s1, 'n');
                  > ... obscurative code ...
                  > if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)[/color]

                  The function cat concatenatiats two "heap" strings allocated by malloc or
                  realloc. You cannot usage cat with an static array as you did. So there is
                  no real need for an size information as long as s1 and s2 are (0
                  terminatet) C strings.

                  The problem occurs if you do the following with cat

                  cat (&string, string [+ n]) /* n <= strlen(string) */

                  Cause of a reallocation (using realloc on string) in cat. The second
                  argument may become invalid. A solution for this Problem might be the
                  following code but im not 100% sure if the test for overlapping is valid

                  char* StrConcat (char ** pS0, const char * const s1)
                  {
                  char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));

                  if (s1) {
                  register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
                  register size_t l1 = strlen (s1);

                  if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
                  /* Check if s1 is part of *pS0 */
                  if (*pS0 + l0 == s1 + l1) {
                  ptrdiff_t d0 = s1 - *pS0;
                  memcpy (pTmp + l0, pTmp + d0, l1);
                  } else {
                  memcpy (pTmp + l0, s1, l1);
                  }
                  pTmp[l0 + l1] = '\000';
                  *pS0 = pTmp;
                  }

                  }

                  return pTmp;
                  }


                  --
                  Michael Knaup

                  Comment

                  • Al Bowers

                    #24
                    Re: realloc



                    Michael Knaup wrote:[color=blue]
                    > However, in general would the restrict qualifier afford
                    >[color=green]
                    >>protection? I am envisioning something like:
                    >>
                    >> char *s2, s1[SIZE] = "some nonsense";
                    >>
                    >> s2 = strchr(s1, 'n');
                    >> ... obscurative code ...
                    >> if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)[/color]
                    >
                    >
                    > The function cat concatenatiats two "heap" strings allocated by malloc or
                    > realloc. You cannot usage cat with an static array as you did. So there is
                    > no real need for an size information as long as s1 and s2 are (0
                    > terminatet) C strings.
                    >
                    > The problem occurs if you do the following with cat
                    >
                    > cat (&string, string [+ n]) /* n <= strlen(string) */
                    >
                    > Cause of a reallocation (using realloc on string) in cat. The second
                    > argument may become invalid. A solution for this Problem might be the
                    > following code but im not 100% sure if the test for overlapping is valid
                    >
                    > char* StrConcat (char ** pS0, const char * const s1)
                    > {
                    > char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
                    >
                    > if (s1) {
                    > register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
                    > register size_t l1 = strlen (s1);
                    >
                    > if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
                    > /* Check if s1 is part of *pS0 */
                    > if (*pS0 + l0 == s1 + l1) {
                    > ptrdiff_t d0 = s1 - *pS0;[/color]

                    I'll mention this again. Isn' t this UB?

                    From the Standard 6.5.6.9
                    "When two pointers are subtracted, both shall point to elements
                    of the same array object, or one past the last element of the
                    array object; the result is the difference of the subscripts of
                    the two array elements".

                    It is quite likely that s1 and *pS0 will NOT be pointers to
                    elements of the same array object.

                    [color=blue]
                    > memcpy (pTmp + l0, pTmp + d0, l1);
                    > } else {
                    > memcpy (pTmp + l0, s1, l1);
                    > }
                    > pTmp[l0 + l1] = '\000';
                    > *pS0 = pTmp;
                    > }
                    >
                    > }
                    >
                    > return pTmp;
                    > }
                    >
                    >[/color]

                    --
                    Al Bowers
                    Tampa, Fl USA
                    mailto: xabowers@myrapi dsys.com (remove the x to send email)
                    Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!


                    Comment

                    • Michael Knaup

                      #25
                      Re: realloc

                      Al Bowers wrote:
                      [color=blue]
                      >
                      >
                      > Michael Knaup wrote:[color=green]
                      >> However, in general would the restrict qualifier afford
                      >>[color=darkred]
                      >>>protection ? I am envisioning something like:
                      >>>
                      >>> char *s2, s1[SIZE] = "some nonsense";
                      >>>
                      >>> s2 = strchr(s1, 'n');
                      >>> ... obscurative code ...
                      >>> if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)[/color]
                      >>
                      >>
                      >> The function cat concatenatiats two "heap" strings allocated by malloc or
                      >> realloc. You cannot usage cat with an static array as you did. So there
                      >> is no real need for an size information as long as s1 and s2 are (0
                      >> terminatet) C strings.
                      >>
                      >> The problem occurs if you do the following with cat
                      >>
                      >> cat (&string, string [+ n]) /* n <= strlen(string) */
                      >>
                      >> Cause of a reallocation (using realloc on string) in cat. The second
                      >> argument may become invalid. A solution for this Problem might be the
                      >> following code but im not 100% sure if the test for overlapping is valid
                      >>
                      >> char* StrConcat (char ** pS0, const char * const s1)
                      >> {
                      >> char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
                      >>
                      >> if (s1) {
                      >> register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
                      >> register size_t l1 = strlen (s1);
                      >>
                      >> if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
                      >> /* Check if s1 is part of *pS0 */
                      >> if (*pS0 + l0 == s1 + l1) {
                      >> ptrdiff_t d0 = s1 - *pS0;[/color]
                      >
                      > I'll mention this again. Isn' t this UB?
                      >
                      > From the Standard 6.5.6.9
                      > "When two pointers are subtracted, both shall point to elements
                      > of the same array object, or one past the last element of the
                      > array object; the result is the difference of the subscripts of
                      > the two array elements".
                      >
                      > It is quite likely that s1 and *pS0 will NOT be pointers to
                      > elements of the same array object.
                      >[/color]

                      I'm not sure but, I think that
                      *pS0 + l0 == *s1 + l1
                      is only true when they both point to the same object and in this case
                      d0 = s1 - *pS0
                      is valid.
                      [color=blue]
                      >[color=green]
                      >> memcpy (pTmp + l0, pTmp + d0, l1);
                      >> } else {
                      >> memcpy (pTmp + l0, s1, l1);
                      >> }
                      >> pTmp[l0 + l1] = '\000';
                      >> *pS0 = pTmp;
                      >> }
                      >>
                      >> }
                      >>
                      >> return pTmp;
                      >> }
                      >>
                      >>[/color]
                      >[/color]

                      --
                      Michael Knaup

                      Comment

                      • Al Bowers

                        #26
                        Re: realloc



                        Michael Knaup wrote:
                        [color=blue]
                        > Al Bowers wrote:
                        >
                        >[color=green]
                        >>
                        >>Michael Knaup wrote:
                        >>[color=darkred]
                        >>>However, in general would the restrict qualifier afford
                        >>>
                        >>>
                        >>>>protectio n? I am envisioning something like:
                        >>>>
                        >>>> char *s2, s1[SIZE] = "some nonsense";
                        >>>>
                        >>>> s2 = strchr(s1, 'n');
                        >>>> ... obscurative code ...
                        >>>> if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)
                        >>>
                        >>>
                        >>>The function cat concatenatiats two "heap" strings allocated by malloc or
                        >>>realloc. You cannot usage cat with an static array as you did. So there
                        >>>is no real need for an size information as long as s1 and s2 are (0
                        >>>terminatet ) C strings.
                        >>>
                        >>>The problem occurs if you do the following with cat
                        >>>
                        >>> cat (&string, string [+ n]) /* n <= strlen(string) */
                        >>>
                        >>>Cause of a reallocation (using realloc on string) in cat. The second
                        >>>argument may become invalid. A solution for this Problem might be the
                        >>>following code but im not 100% sure if the test for overlapping is valid
                        >>>
                        >>>char* StrConcat (char ** pS0, const char * const s1)
                        >>>{
                        >>> char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
                        >>>
                        >>> if (s1) {
                        >>> register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
                        >>> register size_t l1 = strlen (s1);
                        >>>
                        >>> if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
                        >>> /* Check if s1 is part of *pS0 */
                        >>> if (*pS0 + l0 == s1 + l1) {
                        >>> ptrdiff_t d0 = s1 - *pS0;[/color]
                        >>
                        >>I'll mention this again. Isn' t this UB?
                        >>
                        >> From the Standard 6.5.6.9
                        >>"When two pointers are subtracted, both shall point to elements
                        >>of the same array object, or one past the last element of the
                        >>array object; the result is the difference of the subscripts of
                        >>the two array elements".
                        >>
                        >>It is quite likely that s1 and *pS0 will NOT be pointers to
                        >>elements of the same array object.
                        >>[/color]
                        >
                        >
                        > I'm not sure but, I think that
                        > *pS0 + l0 == *s1 + l1
                        > is only true when they both point to the same object and in this case
                        > d0 = s1 - *pS0
                        > is valid.
                        >[/color]

                        After posting, I saw what you have made a change. I tried
                        to cancel the post.

                        I do have one area of concern and would like for you to look
                        at and possiby respond.

                        The expression *pS0 +10 appears to me to be UB when
                        *pS0 is a null pointer. From looking at the flow it seems
                        possible that *pS0 can have the NULL value.

                        The Standard says:
                        1. When an expression that has integer type is added to
                        or subtracted from a pointer, the result has the type of
                        the pointer operand.

                        2. If both the pointer operand and the result point to elements
                        of the same array object, or one past the last element of the
                        array object, the evaluation shall not produce an overflow;
                        otherwise, the behavior is undefined.

                        So the expression (*pS0 + l0) will yield a char *type.
                        And, if *pS0 is a null pointer(value is NULL), then the result,
                        a char *type, would not be pointing to a defined array type as
                        pS0 will not be pointing to a defined array type.

                        Because of this I would change the if statement to:

                        if(*pS0 && (*pS0 + l0 == s1 + l1))

                        [color=blue][color=green][color=darkred]
                        >>> memcpy (pTmp + l0, pTmp + d0, l1);
                        >>> } else {
                        >>> memcpy (pTmp + l0, s1, l1);
                        >>> }
                        >>> pTmp[l0 + l1] = '\000';
                        >>> *pS0 = pTmp;
                        >>> }
                        >>>
                        >>> }
                        >>>
                        >>> return pTmp;
                        >>>}
                        >>>
                        >>>[/color]
                        >>[/color]
                        >[/color]

                        --
                        Al Bowers
                        Tampa, Fl USA
                        mailto: xabowers@myrapi dsys.com (remove the x to send email)
                        Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!


                        Comment

                        • Michael Knaup

                          #27
                          Re: realloc

                          Al Bowers wrote:

                          [color=blue]
                          > if(*pS0 && (*pS0 + l0 == s1 + l1))
                          >[/color]

                          Yes you are right, this must be added, thanks ;-).

                          --
                          Michael Knaup

                          Comment

                          • Al Bowers

                            #28
                            Re: realloc



                            Michael Knaup wrote:
                            [color=blue]
                            > Al Bowers wrote:
                            >
                            >[color=green]
                            >>
                            >>Michael Knaup wrote:
                            >>[color=darkred]
                            >>>However, in general would the restrict qualifier afford
                            >>>
                            >>>
                            >>>>protectio n? I am envisioning something like:
                            >>>>
                            >>>> char *s2, s1[SIZE] = "some nonsense";
                            >>>>
                            >>>> s2 = strchr(s1, 'n');
                            >>>> ... obscurative code ...
                            >>>> if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)
                            >>>
                            >>>
                            >>>The function cat concatenatiats two "heap" strings allocated by malloc or
                            >>>realloc. You cannot usage cat with an static array as you did. So there
                            >>>is no real need for an size information as long as s1 and s2 are (0
                            >>>terminatet ) C strings.
                            >>>
                            >>>The problem occurs if you do the following with cat
                            >>>
                            >>> cat (&string, string [+ n]) /* n <= strlen(string) */
                            >>>
                            >>>Cause of a reallocation (using realloc on string) in cat. The second
                            >>>argument may become invalid. A solution for this Problem might be the
                            >>>following code but im not 100% sure if the test for overlapping is valid
                            >>>
                            >>>char* StrConcat (char ** pS0, const char * const s1)
                            >>>{
                            >>> char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
                            >>>
                            >>> if (s1) {
                            >>> register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
                            >>> register size_t l1 = strlen (s1);
                            >>>
                            >>> if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
                            >>> /* Check if s1 is part of *pS0 */
                            >>> if (*pS0 + l0 == s1 + l1) {
                            >>> ptrdiff_t d0 = s1 - *pS0;[/color]
                            >>
                            >>I'll mention this again. Isn' t this UB?
                            >>
                            >> From the Standard 6.5.6.9
                            >>"When two pointers are subtracted, both shall point to elements
                            >>of the same array object, or one past the last element of the
                            >>array object; the result is the difference of the subscripts of
                            >>the two array elements".
                            >>
                            >>It is quite likely that s1 and *pS0 will NOT be pointers to
                            >>elements of the same array object.
                            >>[/color]
                            >
                            >
                            > I'm not sure but, I think that
                            > *pS0 + l0 == *s1 + l1
                            > is only true when they both point to the same object and in this case
                            > d0 = s1 - *pS0
                            > is valid.
                            >[/color]

                            I had a concern that *pS0 might have value NULL in expression
                            *pS0 + l0. But, I see that it can't so the code looks fine to me.


                            [color=blue][color=green][color=darkred]
                            >>> memcpy (pTmp + l0, pTmp + d0, l1);
                            >>> } else {
                            >>> memcpy (pTmp + l0, s1, l1);
                            >>> }
                            >>> pTmp[l0 + l1] = '\000';
                            >>> *pS0 = pTmp;
                            >>> }
                            >>>
                            >>> }
                            >>>
                            >>> return pTmp;
                            >>>}
                            >>>
                            >>>[/color]
                            >>[/color]
                            >[/color]

                            --
                            Al Bowers
                            Tampa, Fl USA
                            mailto: xabowers@myrapi dsys.com (remove the x to send email)
                            Latest news coverage, email, free stock quotes, live scores and video are just the beginning. Discover more every day at Yahoo!


                            Comment

                            • Michael Knaup

                              #29
                              Re: realloc

                              Al Bowers wrote:
                              [color=blue][color=green]
                              >>[/color]
                              >
                              > I had a concern that *pS0 might have value NULL in expression
                              > *pS0 + l0. But, I see that it can't so the code looks fine to me.
                              >[/color]

                              Sorry, that i've to say that *pS0 == NULL is true if you call Concat
                              in this way

                              char *string = NULL

                              Concat(&string, "ho");

                              So you were right with your concern.
                              --
                              Michael Knaup

                              Comment

                              • Flash Gordon

                                #30
                                Re: realloc

                                Michael Knaup wrote:[color=blue]
                                > However, in general would the restrict qualifier afford
                                >[color=green]
                                >>protection? I am envisioning something like:
                                >>
                                >> char *s2, s1[SIZE] = "some nonsense";
                                >>
                                >> s2 = strchr(s1, 'n');
                                >> ... obscurative code ...
                                >> if ((strlen(s1) + strlen(s2)) < SIZE) cat(s1, s2)[/color]
                                >
                                >
                                > The function cat concatenatiats two "heap" strings allocated by malloc or
                                > realloc. You cannot usage cat with an static array as you did. So there is
                                > no real need for an size information as long as s1 and s2 are (0
                                > terminatet) C strings.
                                >
                                > The problem occurs if you do the following with cat
                                >
                                > cat (&string, string [+ n]) /* n <= strlen(string) */
                                >
                                > Cause of a reallocation (using realloc on string) in cat. The second
                                > argument may become invalid. A solution for this Problem might be the
                                > following code but im not 100% sure if the test for overlapping is valid
                                >
                                > char* StrConcat (char ** pS0, const char * const s1)
                                > {
                                > char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));
                                >
                                > if (s1) {
                                > register size_t l0 = (pTmp ? strlen (pTmp) : 0u);
                                > register size_t l1 = strlen (s1);[/color]

                                Using names l0 and l1 is a horrible thing to do since they look too much
                                like 10 and 11.
                                [color=blue]
                                > if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
                                > /* Check if s1 is part of *pS0 */
                                > if (*pS0 + l0 == s1 + l1) {[/color]

                                If the realloc moves the block then evaluating a pointer in to where is
                                used to be (i.e. *pS0) invokes undefined behaviour. So you need to do
                                this check before the realloc.
                                [color=blue]
                                > ptrdiff_t d0 = s1 - *pS0;[/color]

                                Again, if the block has been moved by the realloc you are evaluating an
                                invalid pointer invoking undefined behaviour. So you need to work this
                                out before the realloc.
                                [color=blue]
                                > memcpy (pTmp + l0, pTmp + d0, l1);
                                > } else {
                                > memcpy (pTmp + l0, s1, l1);
                                > }
                                > pTmp[l0 + l1] = '\000';
                                > *pS0 = pTmp;
                                > }
                                >
                                > }
                                >
                                > return pTmp;
                                > }[/color]

                                How about:
                                #include <stdio.h>
                                #include <string.h>
                                #include <stdlib.h>
                                #include <stddef.h>

                                char* StrConcat (char **pS0, const char *s1)
                                {
                                char *pTmp = (pS0 ? *pS0 : (pS0 = &pTmp, NULL));

                                if (s1) {
                                ptrdiff_t offset;
                                size_t len0 = (pTmp ? strlen(pTmp) : 0);
                                size_t len1 = strlen(s1);
                                int overlapping = 0;

                                /* Check if s1 is part of *pS0 */
                                if (pTmp + len0 == s1 + len1) {
                                overlapping = 1;
                                offset = s1 - pTmp;
                                }

                                if ((pTmp = realloc(pTmp, len0 + len1 + 1))) {
                                if (overlapping)
                                s1 = pTmp + offset;
                                memcpy(pTmp + len0, s1, len1);
                                pTmp[len0 + len1] = '\0';
                                *pS0 = pTmp;
                                }

                                }

                                return pTmp;
                                }

                                int main(void)
                                {
                                char *tmp;
                                char *s = NULL;
                                tmp = StrConcat(&s,"o h");
                                printf("%s\n",t mp);
                                s = StrConcat(&tmp, "haha");
                                printf("%s\n",s );
                                return 0;
                                }
                                --
                                Flash Gordon
                                Living in interesting times.
                                Although my email address says spam, it is real and I read it.

                                Comment

                                Working...