By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,403 Members | 855 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,403 IT Pros & Developers. It's quick & easy.

realloc

P: n/a
Roy
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,strlen(t) + 1);
else
tmp = realloc(s,strlen(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",tmp);
tmp = cat(s,"haha");
printf("%s\n",tmp);
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.

Nov 14 '05 #1
Share this Question
Share on Google+
36 Replies


P: n/a

Roy wrote:
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,strlen(t) + 1);
else
tmp = realloc(s,strlen(s) + strlen(t) + 1);
if (tmp == NULL) {
fputs("realloc error",stderr);
exit(1);
}
while (*tmp++); // search for '\0' and stop
the above statement is not right, when s = null, what do you expect the
*tmp is?
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",tmp);
tmp = cat(s,"haha");
printf("%s\n",tmp);
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.


Nov 14 '05 #2

P: n/a
Roy
baumann@pan wrote:
Roy wrote:
Hi all :
My code below :

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

char *cat(char *s, const char *t)
{
char *tmp;
correct here:
if (s == NULL) {
tmp = realloc(s,strlen(t) + 1);
while(*tmp++ = *t++); // copy *t to *tmp.
} else { tmp = realloc(s,strlen(s) + strlen(t) + 1);
if (tmp == NULL) {
fputs("realloc error",stderr);
exit(1);
}
while (*tmp++); // search for '\0' and stop

the above statement is not right, when s = null, what do you expect
the
*tmp is?
Now handled the s=null but still blanks...
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",tmp);
tmp = cat(s,"haha");
printf("%s\n",tmp);
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.


Nov 14 '05 #3

P: n/a
Roy wrote:

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,strlen(t) + 1);
else
tmp = realloc(s,strlen(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",tmp);
tmp = cat(s,"haha");
printf("%s\n",tmp);
return 0;
}


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

if (s == NULL) {
tmp = realloc(s, strlen(t) + 1);
*tmp = '\0';
} else {
tmp = realloc(s, strlen(s) + strlen(t) + 1);
}
if (tmp == NULL) {
fputs("realloc error",stderr);
exit(EXIT_FAILURE);
}
s = tmp;
while (*tmp++ != '\0') {
;
}
tmp--;
while ((*tmp++ = *t++) != '\0') {
;
}
return s;
}

--
pete
Nov 14 '05 #4

P: n/a


pete wrote:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *tmp;
char *s;

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

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

if (s == NULL) {
tmp = realloc(s, strlen(t) + 1);
*tmp = '\0';


Here is a slight flaw. You do not want to assign to *tmp
BEFORE you have checked tmp value for a possible NULL.
} else {
tmp = realloc(s, strlen(s) + strlen(t) + 1);
}
if (tmp == NULL) {
fputs("realloc error",stderr);
exit(EXIT_FAILURE);
}
s = tmp;
while (*tmp++ != '\0') {
;
}
tmp--;
while ((*tmp++ = *t++) != '\0') {
;
}
return s;
}


This definition will abort the program if dynamic allocation
fails. Another less virulent act on the executable would be
give a signal to the caller, via the return value, or some
other means, that the function was not successful in the
operation.

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

int cat(char **s1, const char *s2);

int main(void)
{
char *s = NULL;

if(cat(&s,"Hello"))
{
if(cat(&s," and Goodbye"))
printf("s = \"%s\"\n",s);
else puts("Memory allocation failure");
}
else puts("Memory allocation failure");
free(s);
return 0;
}

int cat(char **s1, const char *s2)
{
int ret = 0; /* value would indicate failure */

if(s1 && s2)
{
char *tmp;
size_t sz = *s1?strlen(*s1)+strlen(s2)+1:strlen(s2)+1;
if((tmp = realloc(*s1,sz)) != NULL)
{
if(!*s1) *tmp = '\0';
strcat(tmp,s2);
*s1 = tmp;
ret = 1; /* value would indicate success */
}
}
return ret;
}

--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #5

P: n/a
Al Bowers wrote:

pete wrote:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *tmp;
char *s;

s = NULL;
tmp = cat(s,"oh");
printf("%s\n",tmp);
tmp = cat(s,"haha");
Probably would be a better demonstration with
tmp = cat(tmp, "haha");
printf("%s\n",tmp);
return 0;
}

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

if (s == NULL) {
tmp = realloc(s, strlen(t) + 1);
*tmp = '\0';


Here is a slight flaw. You do not want to assign to *tmp
BEFORE you have checked tmp value for a possible NULL.


Thank you.
if (tmp == NULL) {
fputs("realloc error",stderr);
exit(EXIT_FAILURE);
}

This definition will abort the program if dynamic allocation
fails. Another less virulent act on the executable would be
give a signal to the caller, via the return value, or some
other means, that the function was not successful in the
operation.


/* I'm taking another shot. */

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

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

int main(void)
{
char *s;

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

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

if (s == NULL) {
tmp = calloc(1, strlen(t) + 1);
} else {
tmp = realloc(s, strlen(s) + strlen(t) + 1);
}
s = tmp;
if (tmp != NULL) {
while (*tmp++ != '\0') {
;
}
tmp--;
while ((*tmp++ = *t++) != '\0') {
;
}
}
return s;
}

--
pete
Nov 14 '05 #6

P: n/a
pete wrote:

Al Bowers wrote:

pete wrote:

/* I'm taking another shot. */

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

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

int main(void)
{
char *s;

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


/*
** I got it into my head that writing cat using strcat,
** might be cheating in some way, but ...
*/

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

if (s == NULL) {
tmp = calloc(1, strlen(t) + 1);
} else {
tmp = realloc(s, strlen(s) + strlen(t) + 1);
}
s = tmp;
if (s != NULL) {
strcat(s, t);
}
return s;
}

--
pete
Nov 14 '05 #7

P: n/a
Roy wrote:
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,strlen(t) + 1);
At this point, the memory pointed to by tmp will be in a random state.
Also you might as well use malloc since you know s is NULL.
else
tmp = realloc(s,strlen(s) + strlen(t) + 1);
if (tmp == NULL) {
fputs("realloc error",stderr);
exit(1);
}
while (*tmp++); // search for '\0' and stop
So the while loop above could do anything if s is NULL, as it is on your
first call.

Also, you have just had the string searched for a '\0' by calling
strlen, so scanning it again seems a bit silly to me.

Also, please don't use // comments on Usenet. They do not survive line
wrapping and, for your information, were not standard in C89 although
they are a common extension. They are standard in C99, but most
implementations that I am aware of are not conforming C99 implementations.
tmp--; //the position of '\0'
while (*tmp++ = *t++) ;
Again, you know the length and could use memcpy which *may* be more
efficient.
s = tmp;
return s;
}

int main()
{
char *tmp;
char *s;

s = NULL;
tmp = cat(s,"oh");
printf("%s\n",tmp);
tmp = cat(s,"haha");
Here you are using s, but s will still be NULL, and loosing the pointer
you obtained by the previous call to cat.
printf("%s\n",tmp);
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.


Try the following modified version...

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

char *cat(char *s, const char *t)
{
char *tmp;
size_t slen;
size_t tlen = strlen(t);

if (s == NULL)
slen = 0;
else
slen = strlen(s);
tmp = realloc(s,slen + tlen + 1);

if (tmp == NULL) {
free(s); /* improve chances of the fputs not running out of memory */
fputs("realloc error",stderr);
exit(1);
}
memcpy(tmp+slen,t,tlen);
tmp[slen+tlen]='\0';
return tmp;
}

int main(void)
{
char *tmp;
char *s = NULL;
tmp = cat(s,"oh");
printf("%s\n",tmp);
s = cat(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.
Nov 14 '05 #8

P: n/a
pete wrote:
pete wrote:

Al Bowers wrote:
>
> pete wrote:

/* I'm taking another shot. */

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

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

int main(void)
{
char *s;

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


/*
** I got it into my head that writing cat using strcat,
** might be cheating in some way, but ...
*/

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

if (s == NULL) {
tmp = calloc(1, strlen(t) + 1);
} else {
tmp = realloc(s, strlen(s) + strlen(t) + 1);
}
s = tmp;


Why reusing s here, s is only a copy of your s in the main function. So if
you want to change your "main" s you have to use a pointer to a pointer
like All did.
if (s != NULL) {
strcat(s, t);
Maybe the use of malloc/realoc and memcpy is a "little" bit faster than your
solution
}
return s;
}


This one should work

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

#if __STDC_VERSION__ < 199901L
# define restrict
#endif

char* concat (char **s, restrict const char *t)
{
char *tmp = NULL;

if (NULL == t) {
if (NULL != s) {
tmp = *s;
}
} else {
size_t length = 1u + strlen(t);

if (NULL == s || NULL == *s) {
tmp = malloc (length);
if (NULL != tmp) {
memcpy(tmp, t, length);
if (NULL != s) {
*s = tmp;
}
}
} else {
size_t old_len = strlen(*s);
tmp = realloc (*s, old_len + length);
if (NULL != tmp) {
memcpy (tmp + old_len, t, length);
*s = tmp;
}
}
}
return tmp;
}

int main(void)
{
char *string = NULL;
char *tmp;

concat(&string, "oh");
printf ("*%p == %s\n", string, string);
tmp = string;
do {
concat(&string, "haha");
} while (tmp == string);
printf ("*%p (%zd) == %s\n", string, strlen(string), string);

free (string);

return EXIT_SUCCESS;
}
--
Michael Knaup
Nov 14 '05 #9

P: n/a
And true you should check against NULL after calling concat
int main(void)
{
char *string = NULL;
char *tmp;

concat(&string, "oh");
if (NULL == string)
return EXIT_FAILURE;
printf ("*%p == %s\n", string, string);
tmp = string;
do { if (NULL == concat(&string, "haha"))
break;
} while (tmp == string);
printf ("*%p (%zd) == %s\n", string, strlen(string), string);

free (string);

return EXIT_SUCCESS;
}


--
Michael Knaup
Nov 14 '05 #10

P: n/a
Michael Knaup wrote:

pete wrote:
pete wrote:

Al Bowers wrote:
>
> pete wrote: s = cat(s, "haha");
if (s != NULL) {
char *cat(char *s, const char *t)
{
char *tmp;

if (s == NULL) {
tmp = calloc(1, strlen(t) + 1);
} else {
tmp = realloc(s, strlen(s) + strlen(t) + 1);
}
s = tmp;
Why reusing s here,
s is only a copy of your s in the main function. So if
you want to change your "main"
s you have to use a pointer to a pointer
like All did.


I changed the value of s in main this way:
s = cat(NULL, "oh");
s = cat(s, "haha");
I wanted to return either a pointer to memory,
or return NULL, from cat.
free (string);


I like that line of code.

My personal preference is to call free from the same
function that makes the call to *alloc.,
except for lists.

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

int main(void)
{
char *s;
char *old_s;

old_s = s = malloc(sizeof "oh");
if (s != NULL) {
puts(strcpy(s, "oh"));
}
if (s != NULL) {
s = realloc(s, strlen("oh") + sizeof "haha");
} else {
s = calloc(1, sizeof "haha");
}
if (s != NULL) {
puts(strcat(s, "haha"));
} else {
s = old_s;
}
free(s);
return 0;
}

--
pete
Nov 14 '05 #11

P: n/a
pete wrote:
Michael Knaup wrote:

pete wrote:
> pete wrote:
>>
>> Al Bowers wrote:
>> >
>> > pete wrote: >> s = cat(s, "haha");
>> if (s != NULL) { > char *cat(char *s, const char *t)
> {
> char *tmp;
>
> if (s == NULL) {
> tmp = calloc(1, strlen(t) + 1);
> } else {
> tmp = realloc(s, strlen(s) + strlen(t) + 1);
> }
> s = tmp;
Why reusing s here,
s is only a copy of your s in the main function. So if
you want to change your "main"
s you have to use a pointer to a pointer
like All did.


I changed the value of s in main this way:
s = cat(NULL, "oh");
s = cat(s, "haha");


But what happens when the memory allocation in cat fails?
I think we have a memory leckage then, don't we?
I wanted to return either a pointer to memory,
or return NULL, from cat.
free (string);


I like that line of code.

My personal preference is to call free from the same
function that makes the call to *alloc.,
except for lists.


Yes thats always a good idea, and you are free to do so with both solutions.
And yes you can do the whole task in place, but do you wanna mantain this
code?
--
Michael Knaup
Nov 14 '05 #12

P: n/a
Michael Knaup wrote:
pete wrote:
Michael Knaup wrote:
pete wrote:
> pete wrote:
>> Al Bowers wrote:
>> > pete wrote: >> s = cat(s, "haha");
>> if (s != NULL) {
> char *cat(char *s, const char *t)
> {
> char *tmp;
>
> if (s == NULL) {
> tmp = calloc(1, strlen(t) + 1);
> } else {
> tmp = realloc(s, strlen(s) + strlen(t) + 1);
> }
> s = tmp;
I changed the value of s in main this way:
s = cat(NULL, "oh");
s = cat(s, "haha"); But what happens when the memory allocation in cat fails?
I think we have a memory leckage then, don't we?


Yes we do.
I should have used an old_s variable there too.
Especially since the subject is realloc,
and saving the value of the old pointer is very much
a part of using realloc correctly.
My personal preference is to call free from the same
function that makes the call to *alloc.,
except for lists.


Yes thats always a good idea,
and you are free to do so with both solutions.
And yes you can do the whole task in place,
but do you wanna mantain this code?


I don't know.
I can't really see this code
being anything other than a realloc exercise.
Nov 14 '05 #13

P: n/a
Flash Gordon wrote:
/* improve chances of the fputs not running out of memory */


#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;
}

int fput_s(const char *s, FILE *stream)
{
while (*s != '\0') {
if (putc(*s, stream) == EOF) {
return EOF;
}
++s;
}
return 0;
}
Nov 14 '05 #14

P: n/a


Michael Knaup wrote:


Maybe the use of malloc/realoc and memcpy is a "little" bit faster than your
solution

The use of memcpy is certainly a good option. The use of the
malloc/realloc combination is not neccessary. Just use
function realloc to do the allocations(see below).
I believe that was the intent of the OP.

Function cat below, is an attempt rewrite of this function
concat. I believe all the operations are safe.
char* concat (char **s, restrict const char *t)
{
char *tmp = NULL;

if (NULL == t) {
if (NULL != s) {
tmp = *s;
}
} else {
size_t length = 1u + strlen(t);

if (NULL == s || NULL == *s) {
tmp = malloc (length);
if (NULL != tmp) {
memcpy(tmp, t, length);
if (NULL != s) {
*s = tmp;
}
}
} else {
size_t old_len = strlen(*s);
tmp = realloc (*s, old_len + length);
if (NULL != tmp) {
memcpy (tmp + old_len, t, length);
*s = tmp;
}
}
}
return tmp;
}


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

char *cat(char **s1, const char *s2);

int main(void)
{
char *s = NULL;

if(cat(&s,"Hello"))
{
if(cat(&s," and Goodbye"))
printf("s = \"%s\"\n",s);
else puts("Memory allocation failure");
}
else puts("Memory allocation failure");
free(s);
s = cat(NULL,"This string generated with NULL 1st argument");
if(s) printf("s = \"%s\"\n",s);
free(s);
return 0;
}

char *cat(char **s1, const char *s2)
{
char *ret = NULL;

if(s2)
{
char *tmp;
size_t sz1 = (!s1||!*s1)?0:strlen(*s1);
size_t sz2 = strlen(s2);
if((tmp = realloc(s1?*s1:NULL,sz1+sz2+1)) != NULL)
{
memcpy(tmp+sz1,s2,sz2+1);
ret = (s1)?*s1 = tmp:tmp;
}
}
return ret;
}

--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #15

P: n/a
pete wrote:
Flash Gordon wrote:

/* improve chances of the fputs not running out of memory */

#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;
}


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.
Nov 14 '05 #16

P: n/a
Roy wrote:

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,strlen(t) + 1);
else
tmp = realloc(s,strlen(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",tmp);
tmp = cat(s,"haha");
printf("%s\n",tmp);
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.


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.announce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
Nov 14 '05 #17

P: n/a
Al Bowers wrote:
char *cat(char **s1, const char *s2)
{
char *ret = NULL;

if(s2)
{
char *tmp;
size_t sz1 = (!s1||!*s1)?0:strlen(*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. memcpy(tmp+sz1,s2,sz2+1);
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);
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
Nov 14 '05 #18

P: n/a


Michael Knaup wrote:
Al Bowers wrote:

char *cat(char **s1, const char *s2)
{
char *ret = NULL;

if(s2)
{
char *tmp;
size_t sz1 = (!s1||!*s1)?0:strlen(*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.


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.
memcpy(tmp+sz1,s2,sz2+1); memmove(tmp+sz1,s2,sz2+1);

Standard C provides function memmove which is similiar to memcpy
but eliminates the overlap problem.
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);
if ((pTmp = realloc (pTmp, l0 + l1))) {
if (*pS0 == s1) {
memcpy (pTmp + l0, pTmp, l0);
pTmp[l0 << 1] = '\000';
} else {
memcpy (pTmp + l0, s1, l1);
}


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.
*pS0 = pTmp;
}

}

return pTmp;
}

--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #19

P: n/a
Al Bowers wrote:


Michael Knaup wrote:
Al Bowers wrote:

char *cat(char **s1, const char *s2)
{
char *ret = NULL;

if(s2)
{
char *tmp;
size_t sz1 = (!s1||!*s1)?0:strlen(*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.


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.


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
memcpy(tmp+sz1,s2,sz2+1); memmove(tmp+sz1,s2,sz2+1);

Standard C provides function memmove which is similiar to memcpy
but eliminates the overlap problem.
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.
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); 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';
} else {
memcpy (pTmp + l0, s1, l1);
}


I think, this will solve the failure for partial "self-concatenation"
*pS0 = pTmp;
}

}

return pTmp;
}



--
Michael Knaup
Nov 14 '05 #20

P: n/a


Michael Knaup wrote:
Al Bowers wrote:


Michael Knaup wrote:
Al Bowers wrote:

char *cat(char **s1, const char *s2)
{
char *ret = NULL;

if(s2)
{
char *tmp;
size_t sz1 = (!s1||!*s1)?0:strlen(*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.
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.

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


I see. Function realloc may possibly move the allocated space
thus making s2 becoming invalid in cases of "self-concatenation"
or partial "self-concatenation".
memcpy(tmp+sz1,s2,sz2+1);


memmove(tmp+sz1,s2,sz2+1);

Standard C provides function memmove which is similiar to memcpy
but eliminates the overlap problem.
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);
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';

} else {
memcpy (pTmp + l0, s1, l1);
}


I think, this will solve the failure for partial "self-concatenation"


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.
*pS0 = pTmp;
}

}

return pTmp;
}



--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #21

P: n/a
Al Bowers wrote:
.... snip ...
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.


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.com, 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
Nov 14 '05 #22

P: n/a
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)


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
Nov 14 '05 #23

P: n/a


Michael Knaup wrote:
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)

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;


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.

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

}

return pTmp;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #24

P: n/a
Al Bowers wrote:


Michael Knaup wrote:
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)

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;


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.


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.
memcpy (pTmp + l0, pTmp + d0, l1);
} else {
memcpy (pTmp + l0, s1, l1);
}
pTmp[l0 + l1] = '\000';
*pS0 = pTmp;
}

}

return pTmp;
}


--
Michael Knaup
Nov 14 '05 #25

P: n/a


Michael Knaup wrote:
Al Bowers wrote:


Michael Knaup wrote:
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)
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;


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.

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.


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))

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

}

return pTmp;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #26

P: n/a
Al Bowers wrote:

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


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

--
Michael Knaup
Nov 14 '05 #27

P: n/a


Michael Knaup wrote:
Al Bowers wrote:


Michael Knaup wrote:
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)
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;


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.

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.


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.
memcpy (pTmp + l0, pTmp + d0, l1);
} else {
memcpy (pTmp + l0, s1, l1);
}
pTmp[l0 + l1] = '\000';
*pS0 = pTmp;
}

}

return pTmp;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #28

P: n/a
Al Bowers wrote:


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.


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
Nov 14 '05 #29

P: n/a
Michael Knaup wrote:
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)

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);


Using names l0 and l1 is a horrible thing to do since they look too much
like 10 and 11.
if ((pTmp = realloc (pTmp, l0 + l1 + 1u))) {
/* Check if s1 is part of *pS0 */
if (*pS0 + l0 == s1 + l1) {
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.
ptrdiff_t d0 = s1 - *pS0;
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.
memcpy (pTmp + l0, pTmp + d0, l1);
} else {
memcpy (pTmp + l0, s1, l1);
}
pTmp[l0 + l1] = '\000';
*pS0 = pTmp;
}

}

return pTmp;
}


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,"oh");
printf("%s\n",tmp);
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.
Nov 14 '05 #30

P: n/a
Michael Knaup wrote:
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)


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.


I gave the prototype for the cat I was discussing as:

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

which in no way restricts the strings to be in memory allocated by
malloc etc. There is no way, in standard C, to so restrict
parameters, and any code that requires it is a bomb waiting to
explode. It is so silly a practice that I never conceived anyone
would write code requiring it.

--
"If you want to post a followup via groups.google.com, 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
Nov 14 '05 #31

P: n/a


Flash Gordon wrote:
Michael Knaup wrote:

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) {

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.


Yes, this appears to be UB.
ptrdiff_t d0 = s1 - *pS0;

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.
memcpy (pTmp + l0, pTmp + d0, l1);
} else {
memcpy (pTmp + l0, s1, l1);
}
pTmp[l0 + l1] = '\000';
*pS0 = pTmp;
}

}

return pTmp;
}

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) {


(pTmp + len0) has the look of undefined behavior. The flow
of the code seems to indicate that it is possible for tTmp
to have the value of NULL. The additition of len0 to pTmp,
a type char * result, does not appear valid if pTmp
is a null pointer.
Perhaps, to make it safe, use:
if(pTmp && (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,"oh");
printf("%s\n",tmp);
s = StrConcat(&tmp,"haha");
printf("%s\n",s);
return 0;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #32

P: n/a
In article <42***************@yahoo.com>
CBFalconer <cb********@worldnet.att.net> wrote:
I gave the prototype for the cat I was discussing as:
char *cat(restrict char *dst, const char *src);


Just an aside (as I think this whole thread is a bit silly :-) ),
but assuming this is the C99 "restrict", you want to have it
occur elsewhere in the type:

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

or more likely:

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

which matches the C99 strcpy() and strcat() prototypes.

Note that "restrict" is a constraint on the person using the
function: compilers need not, and in general cannot, check whether
the restriction is satisified by any given call.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #33

P: n/a
Chris Torek wrote:
CBFalconer <cb********@worldnet.att.net> wrote:
I gave the prototype for the cat I was discussing as:
char *cat(restrict char *dst, const char *src);


Just an aside (as I think this whole thread is a bit silly :-) ),
but assuming this is the C99 "restrict", you want to have it
occur elsewhere in the type:

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

or more likely:

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

which matches the C99 strcpy() and strcat() prototypes.

Note that "restrict" is a constraint on the person using the
function: compilers need not, and in general cannot, check
whether the restriction is satisified by any given call.


Am I correct if I say the restrict simply warns the user that this
function makes some assumptions about the pointer(s) it is
receiving, and that it is very likely to go howling off into the
boondocks if those assumptions are not met? I.e. it has no more
real effect than a notation in the function documentation.

--
"If you want to post a followup via groups.google.com, 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
Nov 14 '05 #34

P: n/a
Al Bowers wrote:


Flash Gordon wrote:
Michael Knaup wrote:

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) {


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.

Yes, this appears to be UB.
ptrdiff_t d0 = s1 - *pS0;


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.
memcpy (pTmp + l0, pTmp + d0, l1);
} else {
memcpy (pTmp + l0, s1, l1);
}
pTmp[l0 + l1] = '\000';
*pS0 = pTmp;
}

}

return pTmp;
}


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) {


(pTmp + len0) has the look of undefined behavior. The flow
of the code seems to indicate that it is possible for tTmp
to have the value of NULL. The additition of len0 to pTmp,
a type char * result, does not appear valid if pTmp
is a null pointer.


If pTmp is NULL then len0 is 0. Is it legal to add 0 to a NULL pointer?
Perhaps, to make it safe, use:
if(pTmp && (pTmp + len0 == s1 + len1))


Yes, that is definitely safe.

<snip>
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #35

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Chris Torek wrote:
CBFalconer <cb********@worldnet.att.net> wrote:
I gave the prototype for the cat I was discussing as:
char *cat(restrict char *dst, const char *src);


Just an aside (as I think this whole thread is a bit silly :-) ),
but assuming this is the C99 "restrict", you want to have it
occur elsewhere in the type:

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

or more likely:

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

which matches the C99 strcpy() and strcat() prototypes.

Note that "restrict" is a constraint on the person using the
function: compilers need not, and in general cannot, check
whether the restriction is satisified by any given call.


Am I correct if I say the restrict simply warns the user that this
function makes some assumptions about the pointer(s) it is
receiving, and that it is very likely to go howling off into the
boondocks if those assumptions are not met? I.e. it has no more
real effect than a notation in the function documentation.


As I understand it, "restrict" causes certain things to become
undefined behavior that would not have been undefined behavior in the
absence of the "restrict". In other words, it gives the compiler
permission to perform optimizations based on the assumption that those
things will not occur. It then becomes the programmer's
responsibility to ensure that the compiler's assumptions are not
violated. (A conforming compiler could simply ignore "restrict".)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #36

P: n/a
Michael Knaup <Mi***********@iwmh.fraunhofer.de> wrote:
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)


The function cat concatenatiats two "heap" strings allocated by malloc or
realloc.


Well... the first string must be allocated (or a null pointer), since it
is realloc()ed. The second string can come from anywhere, as long as
it's a correct string.

Richard
Nov 14 '05 #37

This discussion thread is closed

Replies have been disabled for this discussion.