Need to find size of destination buffer for strncpy

F

Frodo Baggins

Hi all,
We are using strcpy to copy strings in our app. This gave us problems
when the destination buffer is not large enough. As a workaround, we
wanted to replace calls to strcpy with strncpy. That is, replace calls
to strcpy with say, my_strcpy(dest,src) which will internally find the
destination buffer length.

For this we need to know the destination buffer size. For statically
allocated strings sizeof is returning the length of the array
correctly, but not for malloced strings (char*). Hence we are not able
to replace calls to strcpy with strncpy with appropriate length
parameter.

Is there any other way out? Changing all the static and dynamic
allocations in the application is very very difficult (around 15k
instances will have to be changed).

Regards,
Frodo
 
R

Randy Howard

Hi all,
We are using strcpy to copy strings in our app. This gave us problems
when the destination buffer is not large enough. As a workaround, we
wanted to replace calls to strcpy with strncpy. That is, replace calls
to strcpy with say, my_strcpy(dest,src) which will internally find the
destination buffer length.

For this we need to know the destination buffer size. For statically
allocated strings sizeof is returning the length of the array
correctly, but not for malloced strings (char*). Hence we are not able
to replace calls to strcpy with strncpy with appropriate length
parameter.

$ man strlen
 
U

user923005

Randy said:
$ man strlen

Seems to me that might be helpful for the source buffer size. How is
it going to help with the destination buffer size?

To the OP:
C does not have real arrays for character strings. They do not know
their own length and there is no simple and reliable way to determine
it. You are just going to have to memorize it yourself with a hash map
or something for those strings that are dynamically allocated.
 
M

Mike Wahler

Frodo Baggins said:
Hi all,
We are using strcpy to copy strings in our app. This gave us problems
when the destination buffer is not large enough. As a workaround, we
wanted to replace calls to strcpy with strncpy. That is, replace calls
to strcpy with say, my_strcpy(dest,src) which will internally find the
destination buffer length.

For this we need to know the destination buffer size. For statically
allocated strings sizeof is returning the length of the array
correctly, but not for malloced strings (char*). Hence we are not able
to replace calls to strcpy with strncpy with appropriate length
parameter.

Is there any other way out? Changing all the static and dynamic
allocations in the application is very very difficult (around 15k
instances will have to be changed).

The only way for your program to know how much memory was allocated
dynamically is for you to have it 'remember' it (the argument passed
to 'malloc()'. This would much more feasible if you used macros to
define your allocation sizes.

-Mike
 
S

SM Ryan

# On Wed, 27 Dec 2006 23:09:48 -0600, Frodo Baggins wrote
# > For this we need to know the destination buffer size. For statically
# > allocated strings sizeof is returning the length of the array
# > correctly, but not for malloced strings (char*). Hence we are not able
# > to replace calls to strcpy with strncpy with appropriate length
# > parameter.

Some systems provide a call on a mallocked pointer that gives
a size either of the original malloc or the allocated space
which may be a little bigger. If you have that available, you
can do that in a system dependent manner.

You can also use a malloc wrapper that records the block size with
the block. Otherwise, because of what C is, you're screwed.

Note that for
void a(void) {
...
char z[M];
...
b(z);
...
}
void b(char *x) {
...
you don't have access to M here
unless you provide an explicit way
such as additional parameter to b(z,M).
...
}
 
C

CBFalconer

Frodo said:
We are using strcpy to copy strings in our app. This gave us problems
when the destination buffer is not large enough. As a workaround, we
wanted to replace calls to strcpy with strncpy. That is, replace calls
to strcpy with say, my_strcpy(dest,src) which will internally find the
destination buffer length.

For this we need to know the destination buffer size. For statically
allocated strings sizeof is returning the length of the array
correctly, but not for malloced strings (char*). Hence we are not able
to replace calls to strcpy with strncpy with appropriate length
parameter.

Is there any other way out? Changing all the static and dynamic
allocations in the application is very very difficult (around 15k
instances will have to be changed).

Don't use strncpy - it has some very awkward properties. Use
strlcpy. (See <http://cbfalconer.home.att.net/download/>

Assuming you have malloced the string storage areas to fit the
strings with "field = malloc(strlen(src) + 1);" strlen(field) will
yield the right length. If that is too small you can realloc
before revising field. Otherwise, just remember what you
malloced. You have to know which instances of field are static,
local, or malloced anyhow.

It sounds as if your code is highly disorganized if this is a
problem. Good luck, you'll need it.
 
J

jacob navia

Frodo Baggins a écrit :
Hi all,
We are using strcpy to copy strings in our app. This gave us problems
when the destination buffer is not large enough. As a workaround, we
wanted to replace calls to strcpy with strncpy. That is, replace calls
to strcpy with say, my_strcpy(dest,src) which will internally find the
destination buffer length.

For this we need to know the destination buffer size. For statically
allocated strings sizeof is returning the length of the array
correctly, but not for malloced strings (char*). Hence we are not able
to replace calls to strcpy with strncpy with appropriate length
parameter.

Is there any other way out? Changing all the static and dynamic
allocations in the application is very very difficult (around 15k
instances will have to be changed).

Regards,
Frodo

Replace all your malloc calls with this two functions.
They will allow you to know immediately the size of an
allocated object, besides giving you more security in handling
pointers, since they can give you a hint if the passed
pointer really points to an allocated buffer.
-------------------------------------------------------------cut here
/* this will be written at the end of the allocated block.
If this is overwritten it means something has written
beyond the block */
#define MAGIC 0xFFFF
/* This signature will be written at the start of the
allocated block to avoid freeing memory that wasn't
allocated at all */
#define SIGNATURE 12345678L
/* This variable counts the size of the memory allocated
so far. This is useful for detecting memory leaks */
static long AllocatedMemory;
/* This allocates a block, writing the signature, then
the size of the block. The useful data starts after
those two ints. At the end of the block, the "MAGIC"
number is written to detect overwrites */
void *allocate(int size)
{
register char *r;
register int *ip = NULL;

if (size <= 0)
return NULL;
size += 3 * sizeof(int);
r = malloc((size_t)size);
if (r == NULL)
return NULL;
memset(r, 0, (size_t) size);
AllocatedMemory += size;
ip = (int *) r;
*ip++ = SIGNATURE;
*ip++ = size;
memset(ip, 0, size - 3*sizeof(int));
ip = (int *) (&r[size - sizeof(int)]);
*ip = MAGIC;
return (r + 2 * sizeof(int));
}
/*
This releases a block verifying that it wasn't overwritten
and that it is really a block. It will not free a block
that doesn't fulfill those characteristics.
*/
void release(void *pp)
{
register int *ip = NULL;
int s;
register char *p = pp;
if (p == NULL)
return;
p -= 2 * sizeof(int);
ip = (int *) p;
if (*ip == SIGNATURE) {
*ip++ = 0;
s = *ip;
ip = (int *) (&p[s - sizeof(int)]);
if (*ip != MAGIC) {
fprintf(stderr,"overwritten block size %d\n",s);
}
*ip = 0;
AllocatedMemory -= s;
free(p);
}
else {
fprintf(stderr,"Wrong block passed to release\n");
}
}

/* This will return the size of a block or -1 if it is not
a valid block
*/
int GetSize(void *block)
{
int *ip = block;

ip -= 2;
if (*ip != SIGNATURE)
return -1;
ip++;
return *ip;
}
 
R

Richard Heathfield

CBFalconer said:

Don't use strncpy - it has some very awkward properties. Use
strlcpy.

Please don't recommend non-standard functions without at least pointing out
that they will render the code non-portable. Thank you.
 
R

Richard Heathfield

Frodo Baggins said:
Hi all,
We are using strcpy to copy strings in our app.
Fine.

This gave us problems when the destination buffer is not large enough.

No, strcpy was not the cause of these problems. The cause of these problems
was that the destination buffer is not large enough. The solution is to
make the destination buffer large enough.
As a workaround, we
wanted to replace calls to strcpy with strncpy.

That's a good way to throw away data. It can also be a good way to lose your
null termination if you're not careful.
That is, replace calls
to strcpy with say, my_strcpy(dest,src) which will internally find the
destination buffer length.

When you create the buffer, you know how big it is. Don't Forget.
 
M

Mark McIntyre

CBFalconer said:



Please don't recommend non-standard functions

He didn't - he recommended using some code of his own which is
portable across different implementations.
without at least pointing out that they will render the code non-portable.

I suggest you read the code before making assumptions. :)
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
R

Richard Heathfield

Mark McIntyre said:
He didn't - he recommended using some code of his own which is
portable across different implementations.

Since it invades implementation namespace, I disagree. On the other hand,
since Chuck has a clue or two to spare, he has taken the trouble to
document the fact, so please don't feel I'm getting on his case.

Incidentally, under C90 rules, he also makes a non-portable assumption about
the meaning of the implementation-reserved identifier __cplusplus. This is
not an unreasonable assumption. Nevertheless, strictly speaking, it is
non-portable.

(Finally, in his test driver I would recommend using const for str1 on line
100 and for s2 on line 84, although these are not, strictly speaking,
portability issues.)
 
J

jacob navia

Richard Heathfield a écrit :
Mark McIntyre said:




Since it invades implementation namespace, I disagree.

look heathfield, if the strlcpy function is already defined
in some implementation there is no need for Chuck's version
probably. The porting has been done ALREADY!!!

Your argument is nonsense.
On the other hand,
since Chuck has a clue or two to spare, he has taken the trouble to
document the fact, so please don't feel I'm getting on his case.

You do.
Incidentally, under C90 rules, he also makes a non-portable assumption about
the meaning of the implementation-reserved identifier __cplusplus. This is
not an unreasonable assumption. Nevertheless, strictly speaking, it is
non-portable.

Please tell me a single implementation that uses the identifier
__cplusplus
for another reason than what everyone uses it for!!!

This is, again, pure heathfield.
 
R

Richard Heathfield

jacob navia said:
Richard Heathfield a écrit :

look heathfield, if the strlcpy function is already defined
in some implementation there is no need for Chuck's version
probably. The porting has been done ALREADY!!!

Since there is no ISO C definition of strlcpy, there is no obligation on any
implementor to avoid implementing strlcpy with completely different
semantics to Chuck's version.
Your argument is nonsense.

No, it isn't. Think it through all the way instead of shooting from the hip
all the time.

Please tell me a single implementation that uses the identifier
__cplusplus
for another reason than what everyone uses it for!!!

I don't know of any (which is why I said it's not an unreasonable
assumption), but absence of evidence is not evidence of absence (which is
why I said it's, strictly speaking, non-portable).
This is, again, pure heathfield.

Yes - it's correct and potentially useful information.
 
C

CBFalconer

Richard said:
CBFalconer said:



Please don't recommend non-standard functions without at least
pointing out that they will render the code non-portable. Thank you.

That is pointed out in the <snipped> package I recommended. Since
the package is in source format, and uses only standard C, the
actuality is that it is portable. The only non-portability is the
name.
 
G

Guest

Richard said:
jacob navia said:

I don't know of any (which is why I said it's not an unreasonable
assumption), but absence of evidence is not evidence of absence (which is
why I said it's, strictly speaking, non-portable).

Checking for a C++ compiler using the __cplusplus macro may not be
strictly conforming in C90, but I believe it is currently 100%
portable. It is possible someone will write a malicious C compiler in
the future, but I would be extremely surprised if such a compiler
exists already, because if it did, I would expect it would be common
knowledge on this newsgroup already. Similarly, __STDC_VERSION__ cannot
be used if you wish to keep your code strictly conforming C90, but I
can't remember seeing any objections to it for that reason in this
newsgroup.
 
M

Mark McIntyre

Richard Heathfield a écrit :

look heathfield, if the strlcpy function is already defined
in some implementation there is no need for Chuck's version
probably. The porting has been done ALREADY!!!

The standard does say that functions beginning str... are reserved.
Your point has some merit of course.
Your argument is nonsense.

The argument is based on the C standard. Myself personally, I suspect
RJH overstated his case in his original post and is covering his
tracks a little now, but I forgive him.
Please tell me a single implementation that uses the identifier
__cplusplus
for another reason than what everyone uses it for!!!

Again, strictly speaking this is irrelevant. Its also post-facto - the
C99 standard codifies this use precisely because everyone began to use
it. That doesn't make it valid C90.
This is, again, pure heathfield.

You're a tit, you know that don't you?
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
R

Richard Heathfield

Harald van D?k said:

Similarly, __STDC_VERSION__ cannot
be used if you wish to keep your code strictly conforming C90, but I
can't remember seeing any objections to it for that reason in this
newsgroup.

Actually, that issue does crop up from time to time.
 
C

CBFalconer

Harald said:
.... snip ...

Checking for a C++ compiler using the __cplusplus macro may not be
strictly conforming in C90, but I believe it is currently 100%
portable. It is possible someone will write a malicious C compiler in
the future, but I would be extremely surprised if such a compiler
exists already, because if it did, I would expect it would be common
knowledge on this newsgroup already. Similarly, __STDC_VERSION__ cannot
be used if you wish to keep your code strictly conforming C90, but I
can't remember seeing any objections to it for that reason in this
newsgroup.

#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)

The value of an undefined id is 0.
 
G

Guest

CBFalconer said:
#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)

The value of an undefined id is 0.

A malicious C90 implementation can define __STDC_VERSION__ to 99999999.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,591
Members
45,103
Latest member
VinaykumarnNevatia
Top