They are similar functions, but what is the exact difference between them? The Linux documentation states:
Note: Use kmemdup_nul() instead if the size is known exactly.
Both functions allocate the needed memory through kmalloc() and then place a NUL terminator at the end of the allocated buffer. The only difference between the two is that kstrndup() first calls strnlen() to calculate the length of the string and therefore the needed size, thus scanning the string.
You can see kmemdup_nul() as an optimized version of kstrndup(). If you already know the length of the string, you can avoid the initial scanning and just use kmemdup_nul() passing in the length as argument. This saves time since the string doesn't need to be scanned, and it's the reason why you see that note.
Moreover, kstrndup() saves space if the string is shorter than max, so in case you don't know the length of the string, even though kmemdup_nul() would work as well, you might want to call kstrndup() instead to potentially save space.
You can clearly see from the code that the only difference between the two functions is the call to strnlen(). Here's the source code, from mm/util.c:
/**
* kstrndup - allocate space for and copy an existing string
* #s: the string to duplicate
* #max: read at most #max chars from #s
* #gfp: the GFP mask used in the kmalloc() call when allocating memory
*
* Note: Use kmemdup_nul() instead if the size is known exactly.
*
* Return: newly allocated copy of #s or %NULL in case of error
*/
char *kstrndup(const char *s, size_t max, gfp_t gfp)
{
size_t len;
char *buf;
if (!s)
return NULL;
len = strnlen(s, max);
buf = kmalloc_track_caller(len+1, gfp);
if (buf) {
memcpy(buf, s, len);
buf[len] = '\0';
}
return buf;
}
EXPORT_SYMBOL(kstrndup);
/**
* kmemdup_nul - Create a NUL-terminated string from unterminated data
* #s: The data to stringify
* #len: The size of the data
* #gfp: the GFP mask used in the kmalloc() call when allocating memory
*
* Return: newly allocated copy of #s with NUL-termination or %NULL in
* case of error
*/
char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
{
char *buf;
if (!s)
return NULL;
buf = kmalloc_track_caller(len + 1, gfp);
if (buf) {
memcpy(buf, s, len);
buf[len] = '\0';
}
return buf;
}
EXPORT_SYMBOL(kmemdup_nul);
Related
Imagine having this code and you don't really know what to except in the pointer of char (a string terminated or an array of chars (string not terminated)), is possibile to use strlen function on a safe way that handle not terminated string? (prevent overflows if the input is not a string terminanted) or can you fix it only by knowing the size of what you pass in input? so the function will become foo(char *c, size_t MAXSIZE)?
void foo(char *c) {
a = strlen(c);
}
We never know what really is behind a pointer. It could also only be a pointer to a single character.
Even by passing a size, you could imagine someone passing a bad pointer and an unrelated value.
C is not a safe language, it does not have runtime type checks. You can do anything you want, you can't prevent others from doing anything they want with your functions.
It's not safe to use just strlen if it's not a null-terminated byte string. According to cppreference:
The behavior is undefined if str is not a pointer to a null-terminated byte string.
If you want to cover the case of not null-terminated byte string then you should use the size_t strnlen_s( const char *str, size_t strsz ), which works just like normal strlen with the exception:
that the function returns zero if str is a null pointer and returns strsz if the null character was not found in the first strsz bytes of str.
It is not possible unless you pass the size.
You can avoid crashing, at least - by asking the operating system how much readable memory there is at this address. (Windows: call VirtualQuery. Linux: read /proc/self/maps). But it's not helpful. There can be lots of readable memory after your string that's totally unrelated to your string but just happened to get allocated after it. Finding out how much memory is safe to read doesn't tell you how long the string is.
To check if the buffer contains a null terminator within a maximum number of characters, the memchr function can be used. The following function safe_strlen behaves like the strlen_s function defined by Annex K of the C specification, and uses memchr to find the position of the first (if any) null terminator in the buffer.
#include <stdint.h>
#include <string.h>
/**
* Get the length of a possibly null terminated string, clamped to a maximum.
*
* If \p s is not NULL, searches up to \p maxsize bytes from \p s to find the
* first null terminator, if any.
*
* \param s Start of string.
* \param maxsize Maximum number of bytes to search.
*
* \return 0 if \p s is \c NULL.
* \return \p maxsize if null terminator not found.
* \return length of null terminated string if null terminator found.
*/
size_t safe_strlen(const char *s, size_t maxsize)
{
size_t length = 0;
if (s)
{
#if PTRDIFF_MAX < SIZE_MAX
/* May need to search the buffer in chunks. */
while (maxsize)
#endif
{
const char *e;
size_t pos;
#if PTRDIFF_MAX < SIZE_MAX
if (maxsize > PTRDIFF_MAX)
{
/* Limit size of chunk. */
pos = PTRDIFF_MAX;
}
else
#endif
{
/* This is the final chunk. */
pos = maxsize;
}
/* Search for null terminator in chunk. */
e = memchr(s, 0, pos);
if (e) {
/* Null terminator found. */
pos = e - s; /* position of null terminator in chunk */
#if PTRDIFF_MAX < SIZE_MAX
/* Make this the final chunk. */
maxsize = pos;
#endif
}
/* Update returned length. */
length += pos;
#if PTRDIFF_MAX < SIZE_MAX
/* Advance to next chunk. */
s += pos;
maxsize -= pos;
#endif
}
}
return length;
}
The code is complicated by the necessity to deal with buffer sizes larger than PTRDIFF_MAX if PTRDIFF_MAX is less than SIZE_MAX. The core functionality without the extra safety checks is as follows:
/* less safe version of the above - may result in undefined behavior. */
size_t less_safe_strlen(const char *s, size_t maxsize)
{
size_t length = 0;
if (s)
{
const char *e = memchr(s, 0, maxsize);
if (e)
{
length = e - s;
}
else
{
length = maxsize;
}
}
return length;
}
I have the following code in C now
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere() // read a string from somewhere
// with length, say 20
memcpy(target_str, source_str, length);
The scenario is that target_str is initialized with 50 bytes. source_str is a string of length 20.
If I want to copy the source_str to target_str i use memcpy() as above with length 50, which is the size of target_str. The reason I use length in memcpy is that, the source_str can have a max value of length but is usually less than that (in the above example its 20).
Now, if I want to copy till length of source_str based on its terminating character ('\0'), even if memcpy length is more than the index of terminating character, is the above code a right way to do it? or is there an alternative suggestion.
Thanks for any help.
The scenario is that target_str is initialized with 50 bytes. source_str is a string of length 20.
If I want to copy the source_str to target_str i use memcpy() as above with length 50, which is the size of target_str.
currently you ask for memcpy to read 30 characters after the end of the source string because it does not care of a possible null terminator on the source, this is an undefined behavior
because you copy a string you can use strcpy rather than memcpy
but the problem of size can be reversed, I mean the target can be smaller than the source, and without protection you will have again a undefined behavior
so you can use strncpy giving the length of the target, just take care of the necessity to add a final null character in case the target is smaller than the source :
int length = 50
char *target_str = (char*) malloc(length);
char *source_str = read_string_from_somewhere(); // length unknown
strncpy(target_str, source_str, length - 1); // -1 to let place for \0
target_str[length - 1] = 0; // force the presence of a null character at end in case
If I want to copy the source_str to target_str i use memcpy() as above
with length 50, which is the size of target_str. The reason I use
length in memcpy is that, the source_str can have a max value of
length but is usually less than that (in the above example its 20).
It is crucially important to distinguish between
the size of the array to which source_str points, and
the length of the string, if any, to which source_str points (+/- the terminator).
If source_str is certain to point to an array of length 50 or more then the memcpy() approach you present is ok. If not, then it produces undefined behavior when source_str in fact points to a shorter array. Any result within the power of your C implementation may occur.
If source_str is certain to point to a (properly-terminated) C string of no more than length - 1 characters, and if it is its string value that you want to copy, then strcpy() is more natural than memcpy(). It will copy all the string contents, up to and including the terminator. This presents no problem when source_str points to an array shorter than length, so long as it contains a string terminator.
If neither of those cases is certain to hold, then it's not clear what you want to do. The strncpy() function may cover some of those cases, but it does not cover all of them.
Now, if I want to copy till length of source_str based on its terminating character ('\0'), even if memcpy length is more than the index of terminating character, is the above code a right way to do it?
No; you'd be copying the entire content of source_str, even past the null-terminator if it occurs before the end of the allocated space for the string it is pointing to.
If your concern is minimizing the auxiliary space used by your program, what you could do is use strlen to determine the length of source_str, and allocate target_str based on that. Also, strcpy is similar to memcpy but is specifically intended for null-terminated strings (observe that it has no "size" or "length" parameter):
char *target_str = NULL;
char *source_str = read_string_from_somewhere();
size_t len = strlen(source_str);
target_str = malloc(len + 1);
strcpy(target_str, source_str);
// ...
free(target_str);
target_str = NULL;
memcpy is used to copy fixed blocks of memory, so if you want to copy something shorter that is terminated by '\n' you don't want to use memcpy.
There is other functions like strncpy or strlcpy that do similar things.
Best to check what the implementations do. I removed the optimized versions from the original source code for the sake of readability.
This is an example memcpy implementation: https://git.musl-libc.org/cgit/musl/tree/src/string/memcpy.c
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;
for (; n; n--) *d++ = *s++;
return dest;
}
It's clear that here, both pieces of memory are visited for n times. regardless of the size of source or destination string, which causes copying of memory past your string if it was shorter. Which is bad and can cause various unwanted behavior.
this is strlcpy from: https://git.musl-libc.org/cgit/musl/tree/src/string/strlcpy.c
size_t strlcpy(char *d, const char *s, size_t n)
{
char *d0 = d;
size_t *wd;
if (!n--) goto finish;
for (; n && (*d=*s); n--, s++, d++);
*d = 0;
finish:
return d-d0 + strlen(s);
}
The trick here is that n && (*d = 0) evaluates to false and will break the looping condition and exit early.
Hence this gives you the wanted behaviour.
Use strlen to determine the exact size of source_string and allocate accordingly, remembering to add an extra byte for the null terminator. Here's a full example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *source_str = "string_read_from_somewhere";
int len = strlen(source_str);
char *target_str = malloc(len + 1);
if (!target_str) {
fprintf(stderr, "%s:%d: malloc failed", __FILE__, __LINE__);
return 1;
}
memcpy(target_str, source_str, len + 1);
puts(target_str);
free(target_str);
return 0;
}
Also, there's no need to cast the result of malloc. Don't forget to free the allocated memory.
As mentioned in the comments, you probably want to restrict the size of the malloced string to a sensible amount.
I want to create a program that copies, element by element, one char array to another but the problem is that, if I don´t introduce in the destination array the null character, the program outputs the correct String + weird characters, so my solution was to iterate through with the length of the String + 1 in order to include the null character, is there any way to iterate with the length of the String without having to worry about the null character? The code is as follows:
int copy(char * source, char * destination, unsigned int lengthDestination);
int copy(char * source, char * destination, unsigned int lengthDestination)
{
int i;
for(i = 0; source[i] != '\0'; i++) {
//Count the length of the source array
}
if(i + 1 != lengthDestination){ //i + 1 in order to take into account '\0'
return 1;
}
for(int j = 0; j < lengthDestination; j++) {
destination[j] = source[j];
}
return 0;
}
int main() {
char * source = "Test number 17"; //Length is 15 counting the null character
unsigned int destinationLength = 15;
char destination[destinationLength];
copy(source, destination, destinationLength);
printf("The String source is: %s\n", source);
printf("The String destination is: %s\n", destination);
return 0;
}
You will always need to 'worry' about the null terminator, in the sense that you can't not have a null terminator in your destination C string, and you will always need to explicitly write the null terminator at the end of your new C string.
Even the built-in strcpy method will copy the null terminator character from your original string to the destination string.
#include <stdio.h>
#include <assert.h>
int copy(char * source, char * destination, unsigned int lengthDestination);
int copy(char * source, char * destination, unsigned int lengthDestination)
{
int i;
for(i = 0; source[i] != '\0'; i++) {
destination[i] = source[i];
}
assert(i+1 == lengthDestination);
destination[i+1] = '\0';
return 0;
}
int main() {
char * source = "Test number 17"; //Length is 15 counting the null character
unsigned int destinationLength = 15;
char destination[destinationLength];
copy(source, destination, destinationLength);
printf("The String source is: %s\n", source);
printf("The String destination is: %s\n", destination);
return 0;
}
If you are passing destination previously declared with automatic storage type or as a pointer previously allocated with malloc, calloc or realloc having allocated storage type, and in either case having nchars of storage available, you can implement a fairly robust copy function by simply using snprintf.
Since you are passing the maximum number of characters, including the nul-terminating character as a parameter to your copy function, that dovetails nicely with the size parameter for snprintf. Further, snprintf will insure a nul-terminated string in destination -- even if source is too long to fit in destination. As a benefit, snprintf returns the number of characters copied if there is sufficient storage in destination for source, otherwise it returns the number of characters that would have been copied had destination had sufficient space -- allowing you to determine the number of characters truncated if destination is insufficient to hold your source string.
Before looking at the implementation of copy let's look at a prototype and talk about declaring functions to that they provide a meaningful return, and while up to you, let's also look at the order of parameters and type qualifier for source, e.g.
/* simple strcpy src to dest, returns dest on success and number of chars
* (including nul-termining char) in nchar, returns NULL otherwise.
*/
char *copy (char *dest, const char *src, size_t *nchar);
If you notice, most string functions return a pointer to the destination string on success (or NULL otherwise) which allows you to make immediate use of the return. Next, while not a show-stopper, most string (or memory in general) copy functions place the destination as the first parameter, followed later by the source. I'm sure either Brian Kerrigan or Dennis Ritchie could explain why, but suffice it to say, most copy function parameters are ordered that way.
Notice also that since you are not modifying the source string in copy, it is best to qualify the parameter as const. The const qualifier is more or less a promise you make to the compiler that source will not be modified in copy which allows the compiler to warn if it sees you breaking that promise, while also allowing the compiler to further optimize the function knowing source will not change.
Finally notice your size or my nchar is passed as a pointer above instead of an immediate value. Since a function in C can only return a single value, if you need a way to get a second piece of information back to the caller, pass a pointer as a parameter so the value at that address can be updated within the function making the new value available to the calling function. Here you return a pointer to dest (or NULL) to indicate success/failure while also updating nchar to contain the number of characters in dest (including the nul-terminating character as you passed in a size not a length).
The definition of copy is quite short and simplistic. The only requirement is the source and destination strings not overlap. (neither strcpy or snprintf are defined in that case). The basic flow is to validate both src and dest are not NULL, then handle the case where src is the "empty-string" (e.g. 1st character is the nul-character) and then to copy src to dest using snprintf saving the return in written and then using a simple conditional to determine whether truncation occurred (and warning in that case) and concluding by updating the value pointed to by nchar and returning dest, e.g.
/* simple strcpy src to dest, returns dest on success and number of chars
* (including nul-termining char) in nchar, returns NULL otherwise.
*/
char *copy (char *dest, const char *src, size_t *nchar)
{
if (!src || !dest) { /* validate src & dest not NULL */
fputs ("error: src or dest NULL\n", stderr);
return NULL; /* return NULL on error */
}
if (!*src) /* handle src being an "empty-string" */
*dest = 0, *nchar = 0;
int written = snprintf (dest, *nchar, "%s", src); /* call snprintf */
if ((size_t)written + 1 > *nchar) { /* handle truncated case */
fprintf (stderr, "warning: dest truncated by %zu chars.\n",
(size_t)(written + 1) - *nchar); /* warn with count */
}
else /* src fit in dest, set nchar to no. of chars in dest */
*nchar = (size_t)(written + 1); /* including nul-character */
return dest; /* return dest so available for immediate use */
}
Putting it altogether in a short example that takes the string to copy as the first argument to the program (using "source string" by default if no argument is given), you could do something like the following:
#include <stdio.h>
#define MAXC 16 /* constant for destination length */
/* simple strcpy src to dest, returns dest on success and number of chars
* (including nul-termining char) in nchar, returns NULL otherwise.
*/
char *copy (char *dest, const char *src, size_t *nchar)
{
if (!src || !dest) { /* validate src & dest not NULL */
fputs ("error: src or dest NULL\n", stderr);
return NULL; /* return NULL on error */
}
if (!*src) /* handle src being an "empty-string" */
*dest = 0, *nchar = 0;
int written = snprintf (dest, *nchar, "%s", src); /* call snprintf */
if ((size_t)written + 1 > *nchar) { /* handle truncated case */
fprintf (stderr, "warning: dest truncated by %zu chars.\n",
(size_t)(written + 1) - *nchar); /* warn with count */
}
else /* src fit in dest, set nchar to no. of chars in dest */
*nchar = (size_t)(written + 1); /* including nul-character */
return dest; /* return dest so available for immediate use */
}
int main (int argc, char **argv) {
char *src = argc > 1 ? argv[1] : "source string",
dest[MAXC];
size_t n = MAXC;
if (copy (dest, src, &n))
printf ("dest: '%s' (%zu chars including nul-char)\n", dest, n);
}
(note: the maximum number of characters in dest is kept short intentionally to easily show how truncation is handled -- size as appropriate for your needs)
Example Use/Output
$ ./bin/strcpy_snprintf
dest: 'source string' (14 chars including nul-char)
Showing maximum number of characters that can be copied without warning:
$ ./bin/strcpy_snprintf 123456789012345
dest: '123456789012345' (16 chars including nul-char)
Showing handling source too long for destination:
$ ./bin/strcpy_snprintf 1234567890123456
warning: dest truncated by 1 chars.
dest: '123456789012345' (16 chars including nul-char)
Look things over and let me know if you have further questions. There are at least a dozen different ways to approach a string copy, but given you are passing dest with its own storage and passing the maximum number of characters (including the nul-character) as a parameter, it's hard to beat snprintf in that case.
Easiest way:
char *copy(const char *source, char *destination, size_t lengthDestination)
{
memcpy(destination, source, lengthDestination -1);
destination[lengthDestination -1] = 0;
return destination;
}
I am new to C and working on a project where I need to be able to get a substring but I am having difficulty as there is a compiler warning about the initialisation and a core dump if I attempt to run the program which I am not sure how to resolve.
I have a function called substring which passes in the source string, the start index and to end index.
Below is my substring function.
char *substring(char * src, int from, int to)
{
char * dst = "\0";
strncpy(dst, src+from, to);
return dst;
}
Below is how I am calling the function
char * debug = substring(rowReport[bPartyColIndex], 1, 2);
rowReport is a MYSQL_ROW, and bPartyColIndex is just an int equal 0 to reference the correct column from the MYSQL_ROW.
At the moment the line above has a compiler warning of:
warning: initialization makes pointer from integer without a cast
which I am unable to determine how to fix this warning.
If I try and run the program I then get a coredump which says that it is a segmentation fault within the substring function performing the strncpy.
char * dst = "\0";
strncpy(dst, src+from, to);
That's why there's a segfault. Assigning dst with \0 isn't correct ! Actually, dst isn't big enough to store the src + from bytes. You should allocate it instead:
char *substring(char * src, int from, int to)
{
size_t src_size = to + 1 - from;
char * dst = malloc(src_size); // Assuming str + from is ok
if (dst != 0)
strncpy(dst, src+from, src_size);
return dst;
}
In this case, you will have to free dst :
char * debug = substring(rowReport[bPartyColIndex], 1, 2);
puts(debug);
free(debug);
You need to allocate new memory for your substring, or have the caller pass in the desired buffer. What you're trying won't work, you are never allocating the storage.
You need something like:
char * substring(const char *str, int from, int to)
{
const size_t len = to - from + 1;
char *out = malloc(len + 1);
if(out != NULL)
{
memcpy(out, str + from, len);
out[len] = '\0';
}
return out;
}
Then the caller needs to free() the returned pointer when done with it.
Your substring function, by itself, has some issues. You are not allocating any space for dst and copying into it. That could lead to a seg fault. You are also not checking if either from or to my go beyond the end of string (can be checked with strlen).
You should also check that from is less than to.
First:
char * dst = "\0";
strncpy(dst, src+from, to);
You are writing to a string literal but string literals are immutable in C. This invokes undefined behavior.
Second:
rowReport[bPartyColIndex] has to be a char * but it is of a different type.
You didn't specify the type of rowReport in your question, but assuming it is a char array you have to pass &rowReport[bPartyColIndex] instead of rowReport[bPartyColIndex] to substring function.
I receive a char * buffer which have the lenght of 10.
But I want to concat the whole content in my struct which have an variable char *.
typedef struct{
char *buffer;
//..
}file_entry;
file_entry real[128];
int fs_write(char *buffer, int size, int file) {
//every time this function is called buffer have 10 of lenght only
// I want to concat the whole text in my char* in my struct
}
Something like this :
real[i].buffer += buffer;
How can I do this in C ?
In general, do the following (adjust and add error checking as you see fit)
// real[i].buffer += buffer;
// Determine new size
int newSize = strlen(real[i].buffer) + strlen(buffer) + 1;
// Allocate new buffer
char * newBuffer = (char *)malloc(newSize);
// do the copy and concat
strcpy(newBuffer,real[i].buffer);
strcat(newBuffer,buffer); // or strncat
// release old buffer
free(real[i].buffer);
// store new pointer
real[i].buffer = newBuffer;
You can use strcat(3) to concatenate strings. Make sure you have allocated enough space at the destination!
Note that just calling strcat() a bunch of times will result in a Schlemiel the Painter's algorithm. Keeping track of the total length in your structure (or elsewhere, if you prefer) will help you out with that.
I am not clear. Do you want:
to concatenate every one of the 10 character buffers you receive into one array, pointed at by one real[0].buffer, or
do you want each 10 character buffer to be pointed at by a different real[i].buffer, or
something else?
You will need to allocate enough space for the copy of the buffer:
#include <stdlib.h>
//...
int size = 10+1; // need to allocate enough space for a terminating '\0'
char* buff = (char *)malloc(size);
if (buff == NULL) {
fprintf(stderr, "Error: Failed to allocate %d bytes in file: %s, line %d\n",
size, __FILE__, __LINE__ );
exit(1);
}
buff[0] = '\0'; // terminate the string so that strcat can work, if needed
//...
real[i].buffer = buff; // now buffer points at some space
//...
strncpy(real[i].buffer, buffer, size-1);