Working with NON-NULL terminated strings

G

Grey Alien

I am retrieving BLOBs from a database into an ADT (kinda like a tagged
union) that is capable of holding (null-terminated) strings amongst many
other data types. The BLOBs are represented as a byte stream (i.e. a
char array), but will be stored in the ADT as a string.

The existing API for retrieving data from the ADT assumes that all
strings are null terminated. However, I have a new set of functions that
will retrieve the BLOBs from the ADT, but I want the BLOBs to be
stored in such a way that the extension of storing BLOBs in the ADT will
be "backward compatable" in the sense that the existing functions (that
expect null terminated strings) will continue to "work" (return
meaningless strings rather than causing the app to crash).

In order to do this, I have to convert the byte stream into a "safe"
(i.e. null terminated) string. This is how I have implemented this
requirement:


char * make_safestring(const char* val)
{
size_t size = (val/sizeof(char)) + 1 ;
char * safestr = calloc(size, sizeof(char)) ;
memmove(safestr, val, size);
safestr[size] = '\0' ;
return safestr ;
}


Q1). Will this work as planned - i.e. will allow a byte stream to be
"converted" (i.e. padded with a '\0') so that functions that expect a
null terminated strings will continue to work

Q2). Have I missed anything ?
 
J

Jens Thoms Toerring

Grey Alien said:
I am retrieving BLOBs from a database into an ADT (kinda like a tagged
union) that is capable of holding (null-terminated) strings amongst many
other data types. The BLOBs are represented as a byte stream (i.e. a
char array), but will be stored in the ADT as a string.

I hope you are sure that your data never can contain a zero byte.
The existing API for retrieving data from the ADT assumes that all
strings are null terminated. However, I have a new set of functions that
will retrieve the BLOBs from the ADT, but I want the BLOBs to be
stored in such a way that the extension of storing BLOBs in the ADT will
be "backward compatable" in the sense that the existing functions (that
expect null terminated strings) will continue to "work" (return
meaningless strings rather than causing the app to crash).
In order to do this, I have to convert the byte stream into a "safe"
(i.e. null terminated) string. This is how I have implemented this
requirement:
char * make_safestring(const char* val)
{
size_t size = (val/sizeof(char)) + 1 ;

This here will definitely not do. 'val' is a pointer and its value
(i.e. the place it points to) has nothing to do at all with the
amount of memory you need to make a copy of. Your function needs
a second argument, the length of the "BLOB". Add 1 to that and use
this value for 'size'.
char * safestr = calloc(size, sizeof(char)) ;

First: why use calloc() when you are going to overwrite the
memory directly afterwards and malloc() would do quite nice?
Second: always check the return value of malloc() or calloc(),
they can fail and then you would try in the next step to copy
to the (non-writable and non-existing) address NULL. Third:
sizeif(car) os guaranteed to be 1. If you don't want to rely
on this you would also have to multiply 'size' in the following
line by sizeof(char).
memmove(safestr, val, size);

memcpy() would be enough here, since your source and target
memoy can't overlap. Since memcpy() doesn't need to take this
case into consideration it might be a bit faster. And shouldn't
you copy one byte less - the size of your data seems to be one
byte less, or you would lose your last byte when you do
safestr[size] = '\0' ;

in the next step.
return safestr ;
}
Regards, Jens
 
B

Barry Schwarz

I am retrieving BLOBs from a database into an ADT (kinda like a tagged
union) that is capable of holding (null-terminated) strings amongst many
other data types. The BLOBs are represented as a byte stream (i.e. a
char array), but will be stored in the ADT as a string.

The existing API for retrieving data from the ADT assumes that all
strings are null terminated. However, I have a new set of functions that
will retrieve the BLOBs from the ADT, but I want the BLOBs to be
stored in such a way that the extension of storing BLOBs in the ADT will
be "backward compatable" in the sense that the existing functions (that
expect null terminated strings) will continue to "work" (return
meaningless strings rather than causing the app to crash).

In order to do this, I have to convert the byte stream into a "safe"
(i.e. null terminated) string. This is how I have implemented this
requirement:


char * make_safestring(const char* val)
{
size_t size = (val/sizeof(char)) + 1 ;
char * safestr = calloc(size, sizeof(char)) ;

Here you allocate size bytes. You can refer to an individual byte
with safestr where i can range from 0 to size-1.
memmove(safestr, val, size);
safestr[size] = '\0' ;

Here you overflow your allocated memory and invoke undefined behavior.
There is no byte safestr[size]. The last byte available is
safestr[size-1].
return safestr ;
}


Q1). Will this work as planned - i.e. will allow a byte stream to be
"converted" (i.e. padded with a '\0') so that functions that expect a
null terminated strings will continue to work

Q2). Have I missed anything ?


Remove del for email
 
T

Thad Smith

Grey said:
I am retrieving BLOBs from a database into an ADT (kinda like a tagged
union) that is capable of holding (null-terminated) strings amongst many
other data types. The BLOBs are represented as a byte stream (i.e. a
char array), but will be stored in the ADT as a string.

The existing API for retrieving data from the ADT assumes that all
strings are null terminated. However, I have a new set of functions that
will retrieve the BLOBs from the ADT, but I want the BLOBs to be stored
in such a way that the extension of storing BLOBs in the ADT will be
"backward compatable" in the sense that the existing functions (that
expect null terminated strings) will continue to "work" (return
meaningless strings rather than causing the app to crash).

I don't understand. You say that strings are stored null-terminated and
that the API expects null-terminated strings. What's the problem?
 
S

santosh

Grey said:
I am retrieving BLOBs from a database into an ADT (kinda like a tagged
union) that is capable of holding (null-terminated) strings amongst many
other data types. The BLOBs are represented as a byte stream (i.e. a
char array), but will be stored in the ADT as a string.

The existing API for retrieving data from the ADT assumes that all
strings are null terminated. However, I have a new set of functions that
will retrieve the BLOBs from the ADT, but I want the BLOBs to be
stored in such a way that the extension of storing BLOBs in the ADT will
be "backward compatable" in the sense that the existing functions (that
expect null terminated strings) will continue to "work" (return
meaningless strings rather than causing the app to crash).

In order to do this, I have to convert the byte stream into a "safe"
(i.e. null terminated) string. This is how I have implemented this
requirement:


char * make_safestring(const char* val)
{
size_t size = (val/sizeof(char)) + 1 ;

val is a pointer. It can hold no information about the size of the
object it points to. The above calculation will yield meaningless
result in size. To allocate the proper number of bytes, you should
pass a second argument to the function which tells it the size of the
object pointed to by val.
char * safestr = calloc(size, sizeof(char)) ;

sizeof(char) is by definition one.
memmove(safestr, val, size);

The allowable subscripts for the array pointed to by safestr is from 0
to one less than size. Though you can set a pointer to point to one
element past an array, you cannot deference it without invoking
undefined behaviour.
safestr[size] = '\0' ;

Same as above.
return safestr ;
}


Q1). Will this work as planned - i.e. will allow a byte stream to be
"converted" (i.e. padded with a '\0') so that functions that expect a
null terminated strings will continue to work

Q2). Have I missed anything ?

Yes. Your calculation of the size of the byte stream is wrong and your
indexing past the end of an array.
 

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,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top