printf() won't print string in c - c

I'm trying to print a char array after a for loop to see the output to make sure it's correct. However, it won't print the string. Why won't it print the string? Am I missing something? It prints the index println string but not the Tag bit won't print. What am I missing?
Here is my code
char *getTag(char *address){
char *binary, *resultsIndex, *resultsTag, *resultsOffset;
char* tags;
int i, j, t;
printf("Get Tag function\n");
binary = hexToBin(address);
printf("Binary : %s\n", binary);
printf("Tag : %i\n", TAG);
printf("Offset : %i\n", OFFSET);
/*Seperate index, tag and offset*/
i = 0;
resultsIndex = (char * )malloc(sizeof(char) * INDEX);
for(i = 0; i < INDEX; i++){
resultsIndex[i] = binary[i];
}
resultsTag = (char * )malloc(sizeof(char) * TAG);
//resultsTag = '\0';
for(t = INDEX; t < TAG + 1; t++){
resultsTag[t] = binary[t];
printf("binary[i] %c\n", binary[t]);
printf("resultsTag[i] %c\n", resultsTag[t]); //<----prints individual character
}
printf("Index bit: %s\n", resultsIndex);
printf("Tag Bit %s", resultsTag); //<-----Won't print the string
return resultsTag;
}
I tried googling the problem and have tried some of the methods. One to make resultsTag[t] = '\0'. I tried that and it won't print still. Is something wrong with my for loop that can cause that?
It prints the individual character inside the loop, so I can see that it is storing it but it won't print it outside the loop. Any advice that could be helpful?

You write toresultTag starting from an offset INDEX, but attempt to print it from the initialised start. If the start happens to contain zero, it will print nothing.
Moreover, the final print does not end in a newline and the output stream is not flushed so will not be displayed immediately on some systems.

If I understand correctly, you are trying to split a string at two defined points, right? It appears you have a string in binary which has the following format:
XXXXYYYYYYZZZ0
^ ^ ^ ^
| | | \String terminator
| | \Offset
| \Tag
\Index
The length of the individual parts is of course just an example because I don't see your constant values. But according to my example, you may have the variables defined like this (specifying the end of them in the string):
#define INDEX 4
#define TAG 10
#define OFFSET 13
Now what the first problem is why it immediately doesn't work for you: You are not constructing resultsTag correctly. But let's first take a look at resultsIndex.
resultsIndex kind of works, but it also not done correctly. I'll explain you why. You are doing this:
resultsIndex = (char * )malloc(sizeof(char) * INDEX);
for(i = 0; i < INDEX; i++){
resultsIndex[i] = binary[i];
}
What it does:
Allocate INDEX (4 in my example) characters for the result string.
Loop from 0 to INDEX (4) exclusively, i.e. INDEX - 1 (3) inclusively and copy the data.
So i will get the values 0..1..2..3 during the loop. This means it will copy all characters from positions 0-3 in binary to positions 0-3 in resultsIndex.
After this part, resultsIndex is defined with a size of 4 characters (if we keep to my example values above) and looks like this:
____ << defined size
XXXX
...which is the index part of the string you copied. However, one mistake here is already that there is no string terminator! It should look like this:
_____ << defined size
XXXX0
^
\string terminator
A string terminator is what tells to whatever/whoever is reading the string later that it ends here and they have to stop reading there, otherwise they would read beyond the end.
However, because nothing stands alone but is normally surrounded by other parts of the memory, I guess it happened to look like this:
____ << defined size
XXXX00000000000...
^ ^
| \you were lucky that those null bytes were around
\this part you actually allocated
But you shouldn't rely on that. It might as well have looked like this:
____ << defined size
XXXXgarbage...
...then it would have printed XXXXgarbage instead of just XXXX. Or:
____ << defined size
XXXX| << here the memory block actually ends
...then it would have crashed trying to print it.
So, to fix this, you would have to reserve one more byte and fill it with a zero value, which acts as string terminator:
resultsIndex = (char * )malloc(sizeof(char) * (INDEX + 1));
for(i = 0; i < INDEX; i++){
resultsIndex[i] = binary[i];
}
resultsIndex[INDEX] = 0; // string terminator
OK now back to resultsTag. In my example above (and it looks like you are doing it similarly), my constant TAG was defined as 10, which is basically the length of the part before the tag (the index: 4) and the tag itself (6) together. But the tag itself is only 6 characters (= TAG - INDEX).
At the moment, you are doing this (I removed some things for clarity):
resultsTag = (char * )malloc(sizeof(char) * TAG);
for(t = INDEX; t < TAG + 1; t++){
resultsTag[t] = binary[t];
printf("resultsTag[i] %c\n", resultsTag[t]);
}
What it does:
Allocate TAG (10 in my example) bytes for the result string.
Loop from INDEX (4 in my example) to TAG + 1 (11) exclusively, i.e. TAG inclusively (10), so actually one char after the end of the tag.
So, the variable t will get the values 4..5..6..7..8..9..10 during the loop.
Effectively, this copies the data from positions 4-10 in binary to positions 4-10 in resultsTag.
The last part is the reason why it doesn't print (but that's not the only problem in your code). After this loop, the memory starting at where resultsTag is located will look like this:
__________ << defined size
????YYYYYYZ
^ ^ ^
| | \this is actually written outside of the allocated block of memory
| \this are the 6 characters of the tag you copied
\you never wrote to this part, so nobody knows what is there
Following my assumption from earlier, that memory you are allocating using malloc is implicitely filled with zero bytes by the system (which, again, is nothing you should rely on), it is likely that it actually looks like this:
__________ << defined size
0000YYYYYYZ
^ ^ ^
| | \this is actually written outside of the allocated block of memory
| \this are the 6 characters of the tag you copied
\zero values - remember that they act as string terminator!
So what happens when you try to print resultsTag? The system will look at the memory and say: OK, let's print. What is the first character? ...Oh, a string terminator already? Well that was short! Nothing to print! Good night.
And so nothing gets printed because your string starts with a red flag saying "string ends here". :P
So this last part has three problems:
You are allocating the wrong amount of memory and start writing to the middle of it instead of from the beginning.
You write beyond the end of it (because of TAG + 1 in the loop).
You again don't terminate the string.
Let me fix it:
resultsTag = (char * )malloc(sizeof(char) * (TAG - INDEX + 1));
for(t = INDEX; t < TAG; t++){
resultsTag[t - INDEX] = binary[t];
printf("resultsTag[i] %c\n", resultsTag[t - INDEX]);
}
resultsTag[TAG] = 0; // string terminator
For sake of completeness, here is what it does:
Allocate memory for the length of the tag only (not index plus tag), plus 1 byte for the string terminator. In my example it would be 6+1=7 bytes.
Loop from INDEX (4 in my example) to TAG (10) exclusively, i.e. TAG - 1 inclusively (9), but we don't use the same index for source and destination of the copying:
The variable t will get the values 4..5..6..7..8..9 during the loop, but the destination index will start at 0, not 4 this time, and will go through 0..1..2..3..4..5.
Effectively, this copies the data from positions 4-9 in binary to positions 0-5 in resultsTag.
So, resultsTag will look like this:
_______ << defined size
YYYYYY0
It would probably be a bit less confusing if TAG weren't defined as "length of index plus length of tag" but just as the length of the tag, because then the calculations were simpler and more obvious, but I'll leave that as an exercise ;)
I can see several other issues with your code too:
1) You are leaking memory because resultsIndex is not freed (i.e. free(resultsIndex); resultsIndex = NULL;) after you finished using it. If you really want to get only the tag (as the function name getTag suggests), you wouldn't need the whole part with resultsIndex at all, though... I don't know what you do with the value of resultsTag after returning it, but you have to make sure that the caller frees it as well!
2) Actually, binary smells like another memory leak. How does hex2bin allocate the memory for the string it returns? If it's also just malloc and there is no magic memory management, you would need to use free(binary); at the end as well.
3) i = 0; is superflouous because you set it to zero two lines below this as well.

First of all you are accessing your resultTag malloc-ated array out of bounds due to condition: t < TAG + 1; You have to loop until TAG-1 to leave space for null terminator. Or malloc TAG+1 bytes.
Secondly you must add a null terminator to your string to make it a C-String.
resultsTag = malloc(sizeof(char) * TAG+1);
for(t = INDEX; t < TAG; t++)
{
resultsTag[t] = binary[t];
printf("binary[i] %c\n", binary[t]);
printf("resultsTag[i] %c\n", resultsTag[t]); //<----prints individual character
}
resultsTag[t] = '\0';
Same considerations for resultsIndex
resultsIndex = (char * )malloc(sizeof(char) * INDEX+1);
for(i = 0; i < INDEX; i++){
resultsIndex[i] = binary[i];
}
resultsIndex[i] = '\0';
As Clifford points out the loop start filling your string from INDEX, then you must print the string starting from that offset.
printf("Tag Bit %s\n", &resultsTag[INDEX]);
or change the assignment inside the loop:
resultsTag[t-INDEX] = binary[t];
Furthermore you have to be sure that all values pointed by binary are ASCII.

You need to flush stdout, or add a \n (stdout autoflush on new-line)
printf("Tag Bit %s\n", resultsTag); //<-----Won't print the string
fflush (stdout);

Related

Function to Split a String into Letters and Digits in C

I'm pretty new to C, and I'm trying to write a function that takes a user input RAM size in B, kB, mB, or gB, and determines the address length. My test program is as follows:
int bitLength(char input[6]) {
char nums[4];
char letters[2];
for(int i = 0; i < (strlen(input)-1); i++){
if(isdigit(input[i])){
memmove(&nums[i], &input[i], 1);
} else {
//memmove(&letters[i], &input[i], 1);
}
}
int numsInt = atoi(nums);
int numExponent = log10(numsInt)/log10(2);
printf("%s\n", nums);
printf("%s\n", letters);
printf("%d", numExponent);
return numExponent;
}
This works correctly as it is, but only because I have that one line commented out. When I try to alter the 'letters' character array with that line, it changes the 'nums' character array to '5m2'
My string input is '512mB'
I need the letters to be able to tell if the user input is in B, kB, mB, or gB.
I am confused as to why the commented out line alters the 'nums' array.
Thank you.
In your input 512mB, "mB" is not digit and is supposed to handled in commented code. When handling those characters, i is 3 and 4. But because length of letters is only 2, when you execute memmove(&letters[i], &input[i], 1);, letters[i] access out of bounds of array so it does undefined behaviour - in this case, writing to memory of nums array.
To fix it, you have to keep unique index for letters. Or better, for both nums and letters since i is index of input.
There are several problems in your code. #MarkSolus have already pointed out that you access letters out-of-bounds because you are using i as index and i can be more than 1 when you do the memmove.
In this answer I'll address some of the other poroblems.
string size and termination
Strings in C needs a zero-termination. Therefore arrays must be 1 larger than the string you expect to store in the array. So
char nums[4]; // Can only hold a 3 char string
char letters[2]; // Can only hold a 1 char string
Most likely you want to increase both arrays by 1.
Further, your code never adds the zero-termination. So your strings are invalid.
You need code like:
nums[some_index] = '\0'; // Add zero-termination
Alternatively you can start by initializing the whole array to zero. Like:
char nums[5] = {0};
char letters[3] = {0};
Missing bounds checks
Your loop is a for-loop using strlen as stop-condition. Now what would happen if I gave the input "123456789BBBBBBBB" ? Well, the loop would go on and i would increment to values ..., 5, 6, 7, ... Then you would index the arrays with a value bigger than the array size, i.e. out-of-bounds access (which is real bad).
You need to make sure you never access the array out-of-bounds.
No format check
Now what if I gave an input without any digits, e.g. "HelloWorld" ? In this case nothin would be written to nums so it will be uninitialized when used in atoi(nums). Again - real bad.
Further, there should be a check to make sure that the non-digit input is one of B, kB, mB, or gB.
Performance
This is not that important but... using memmove for copy of a single character is slow. Just assign directly.
memmove(&nums[i], &input[i], 1); ---> nums[i] = input[i];
How to fix
There are many, many different ways to fix the code. Below is a simple solution. It's not the best way but it's done like this to keep the code simple:
#define DIGIT_LEN 4
#define FORMAT_LEN 2
int bitLength(char *input)
{
char nums[DIGIT_LEN + 1] = {0}; // Max allowed number is 9999
char letters[FORMAT_LEN + 1] = {0}; // Allow at max two non-digit chars
if (input == NULL) exit(1); // error - illegal input
if (!isdigit(input[0])) exit(1); // error - input must start with a digit
// parse digits (at max 4 digits)
int i = 0;
while(i < DIGITS && isdigit(input[i]))
{
nums[i] = input[i];
++i;
}
// parse memory format, i.e. rest of strin must be of of B, kB, mB, gB
if ((strcmp(&input[i], "B") != 0) &&
(strcmp(&input[i], "kB") != 0) &&
(strcmp(&input[i], "mB") != 0) &&
(strcmp(&input[i], "gB") != 0))
{
// error - illegal input
exit(1);
}
strcpy(letters, &input[i]);
// Now nums and letter are ready for further processing
...
...
}
}

Memcpy and splitting up a string from a pointer array

I am attempting to split up a string allocated to a pointer array and assign it into a matrix array. The number of characters that get assigned to the array are dependent on the number (bytes) entered by the user, so I can't use a function like strtok() to split up the string, since I don't have an actual delimeter.
Anyways, if the number of bytes entered are 1, I can successfully fill my "matrix" from start to finish.
My issue comes when the input is either 2 or 4. For some reason, the code skips over the first character in my original pointer array, and starts at the second. A suspicion I had was that since memcpy() skips over the first char because it is stored at the pointer. I thought this might be the case since technically pointer arrays are not arrays but pointers to arrays, but that wouldn't really explain why the first char gets stored when the input byte is 1.
Below is a little snippet of my code, which includes the dynamic array allocation, and use of memcpy().
Here is where I allocated the string and read in from a file:
char * fileArray = (char*)malloc(size*sizeof(char));
if (fileArray== NULL){
printf("NULL");
return 1;
}
fgets(fileArray, size+1, fp);
After a few lines in between, which calculated the amount of columns I would have to allocate for the matrix, I tried using memcpy.
char maTrix[numOfCols][bytes];
if (bytes == 1){
for (i = 0; i<numOfCols; i++) {
memcpy(&maTrix[i], &fileArray[i], bytes);
}
}
else if (bytes == 2 || bytes == 4) {
for (i = 0; i < numOfCols; i++) {
int k = i * bytes;
int p = k + bytes;
while (k < p) {
memcpy(&maTrix[i], &fileArray[k], bytes);
k++;
}
}
}
If my original theory is right, how would I go about correcting this issue?
The input file I am using contains something like this:
The highest forms of understanding we can achieve are laughter and human compass
ion. Richard Feynman
To make clearer what I am trying to do, is to basically split the total number of characters into columns of n bytes (read chars) each. I have padded the # of characters so that n should always be divisible by the string.
I'm looking for an output of something like this.
if bytes == 2:
maTrix[0][0] = 'T'
maTrix[0][1] = 'h'
maTrix[1][0] = 'e'
maTrix[1][1] = ' '
maTrix[2][0] = 'h'
And so on until the whole matrix is filled.
Instead I get:
maTrix[0][0] = 'h'
maTrix[0][1] = 'e'
maTrix[1][0] = ' '
maTrix[1][1] = 'h'
maTrix[2][0] = 'i'
The same is expected for an input of 4 bytes, just with less columns and 4 rows.

Is there a better way of modifying arrays from within a function in C?

I am trying to create a formatted string , however I do not know why I cannot print global array which I have modified inside the function.Also the strange behavior is that I cannot access only a specific global array (rand_session_key) rest of the other global arrays are behaving as normal(similar operations are being done on them except their size varies) and I can access their value properly. This code is run on an esp32 (DOIT Dev Kit V1) (with Arduino-Core) , when I run this program on my computer (modifying a few functions etc.) the result is what I expect , I think I am overlapping the characters in the memory or accessing it the wrong way , but had it been the case I would not have yielded the expected output on my computer.
I tried to modify my program and made it more verbose. Also I ran the same code (with some obvious modifications to make it run on my computer) , and the result is good as expected.
char persistent_peripheral_id[] = "FRUCTOSE96";
char rand_session_iden[7] = {'\0'};
char rand_session_key[17] = {'\0'};
char rand_session_channel[3] = {'\0'};
char *generate_random_session_identifier(char *rand_session_iden_local)
{
srand(time(NULL));
int counter = 0;
for (counter = 0; counter < 6; counter++)
*(rand_session_iden_local + counter) = (random(10) % ('~' - ' ')) + 'k';
rand_session_iden_local[counter] = '\0';
printf("Identifier : %s\n", rand_session_iden); //acessing global defintion of array everything is good until here
return &rand_session_iden_local[0];
}
char *generate_random_session_key(char *rand_session_key_local)
{
srand(time(NULL));
int counter = 0;
for (counter = 0; counter < 16; counter++)
*(rand_session_key_local + counter) = (random(10) % ('~' - ' ')) + 'b';
rand_session_key_local[counter] = '\0';
printf("Key : %s\n", rand_session_key);//acessing global defintion of array everything is good until here
return &rand_session_key_local[0];
}
char *generate_random_session_channel(char *rand_session_channel_local)
{
srand(time(NULL));
int channel_value = random(100);
sprintf(rand_session_channel_local, "%03ld", channel_value);
printf("Channel : %s\n", rand_session_channel);//acessing global defintion of array everything is good until here
return &rand_session_channel_local[0];
}
void begin_exchange_package()
{
//If this does not works here (observe rand_session_key) , it will not work for sprintf also ??
printf("\n %s-%s-%s-%s \n", (char *)persistent_peripheral_id,
generate_random_session_identifier(rand_session_iden),
generate_random_session_key(rand_session_key),
generate_random_session_channel(rand_session_channel));
//Notice it prints here ????
printf("\n %s \n",generate_random_session_key(rand_session_key));
Serial.println("Done");
//sprintf((char *)plain_text_package, "{\"p\":\"%s\",\"r\":\"%s\",\"k\":\"%s\",\"c\":\"%s\"}", (char *)persistent_peripheral_id,(char *)rand_session_iden, (char *)rand_session_key , (char *)rand_session_channel);
}
void setup()
{
Serial.begin(115200);
begin_exchange_package();
}
void loop()
{
}
The Output is
FRUCTOSE96-tnltkp--094
Where I expected all the 4 arrays to be printed ?? but it does print separately , is my array being terminated in the wrong way ?? also the logic to assign a random character will always yield a printable ASCII Character (I learned this from a forum on esp32's website)
This code ...
sprintf(rand_session_channel_local, "%03ld", channel_value);
... requires rand_session_channel_local to point to an array of at least four characters, because at will print at least three digits plus a string terminator. The array into which it points, rand_session_channel, is only three characters long. The resulting behavior is undefined.
The observed manifestation of the UB is consistent with the global arrays being laid out in memory such that rand_session_key immediately follows rand_session_channel, such that overflowing the latter means that the string terminator is written to position 0 of the former, making it an empty string. Note, however, that you cannot rely on predicting manifestations of UB, nor is it generally of much use to analyze them. Instead, avoid exercising UB.
It's unclear what random function you are using, since the C standard library's does not take an argument, but if the argument to yours specifies an exclusive upper bound then you could just change the sprintf format to "%02ld". Alternatively, increase the size of rand_session_channel to at least 4.

C - Value seems to pass to array element correctly but doesn't

Sorry I know that's a really badly worded question - I just couldn't think of a better way to say it.
I have asked this here as I cannot seem to word it correctly to find a solution my Googling.
Code explanation:
Separates file name 'echo' from file_name char array. file_name contains 'echo x y'
The loop starts at 'x' which is the previous file names length +1 (for the space).
The while loop loops until the next space is seen. The null char is to ensure the loop ends when the end of file_name is hit.
It assigns the value of file_name to arg_tmp until it hits a space then assigns this word / letter to the argv array
It then ++ the current_arg counter for the next arg
Hopefully this makes sense and there is enough code there to identify the problem.
MAX_FILE_NAME_LENGTH is 14
strlen(exec_name) = 4 so the +1 makes it 5.
Length is 9.
Here is my code :
void
setup_argv(const char *file_name, char *argv[], size_t argc, size_t length)
{
char exec_name[MAX_FILE_NAME_LENGTH];
char arg_tmp[MAX_FILE_NAME_LENGTH]; // temp arg holder
// get file name
get_exec_name(file_name, exec_name);
// add file name to argv
argv[0] = exec_name;
// get rest of args
// +1 - start at first character of next arg
int current_arg=1;
for(size_t i = strlen(exec_name)+1; i < length; i++)
{
size_t j = 0;
while(!(file_name[i] == NULL_CHAR || file_name[i] == SPACE))
{
arg_tmp[j] = file_name[i];
printf("::WHILE::%s\n", arg_tmp);
i++;
}
printf("::BOTH::%d %s\n", current_arg, arg_tmp);
arg_tmp[++j] = NULL_CHAR;
argv[current_arg] = arg_tmp;
printf("::ARGV CUR ARG::%s\n", argv[current_arg]);
printf("::ARGV::%s\n", argv[1]);
printf("::CUR ARG::%d\n", current_arg);
current_arg++;
printf("::CUR ARG::%d\n", current_arg);
}
printf("::ARGV ALL::%s %s %s\n", argv[0], argv[1], argv[2]);
}
Here is my output:
::WHILE::x
::BOTH::1 x
::ARGV CUR ARG::x
::ARGV::x
::CUR ARG::1
::CUR ARG::2
::WHILE::y
::BOTH::2 y
::ARGV CUR ARG::y
::ARGV::y
::CUR ARG::2
::CUR ARG::3
::ARGV ALL::echo y y
What should be printed in the last line is 'echo x y'.
I have used print statements to debug it and try to find where it goes wrong - but I can't seem to see it.
For some reason, it's printing and passing in y twice.
Why is this? What am I doing wrong?
EDIT : As I have now figured out - I cannot use malloc or strdup (unless I write my own functions for these). This is because I am doing an operating systems modules coursework. Is there alternatives methods or should I look for written functions of these?
The variable argv is an array of pointers, and you make all pointers in the loop point to the very same place, the first element of arg_temp.
This is even worse than you think, because when setup_argv returns, then the lifetime of arg_temp ends and it ceases to exist, leaving you with an array of stray and invalid pointers. Attempting to dereference them will lead to undefined behavior.
As a solution I suggest you use the common strdup function, or make up your own string-duplication function which allocates new memory for the strings.
Lastly, for a correct argv style array, you should terminate it with a null pointer.

Coverity deflect: - String length miscalculation (BAD_ALLOC_STRLEN)

I have a coverity deflect to be fixed but I am not sure about it. I have a function (void my_function(a_type *my_variable)) with the following problematic line of code:
body = malloc(strlen(&((my_type*) *my_variable)->Param2.body[1]) +1);
where body is an unsigned char*.
The Coverity message:
String length miscalculation (BAD_ALLOC_STRLEN)
Using "strlen(((my_type *)*my_variable)->Param2.body + 1)"
instead of "strlen(((my_type *)*my_variable)->Param2.body) + 1"
as an argument to "malloc" might be an under-allocation.
Now, given the strlen function call, which looks like this:
strlen(&((my_type*) *my_variable)->Param2.body[1])
and this line is identical to:
strlen(&((my_type*) *my_variable)->Param2.body + 1)
So this should be changed according to the message, and the result would be:
body = malloc((strlen(&((my_type*) *my_variable)->Param2.body)+1) +1);
Why is bad such an argument for malloc? I do not see what is the actual problem here so I am unsure about this solution and/or its necessity.
Additional information is that, &((my_type*) *my_variable)->Param2.body[1] (simply &Param2.body[1]) will be copied into body using strcpy, like:
strcpy(body, &((my_type *) *my_variable)->Param2.body[1]);
No, ...body[1] and ...body + 1 are not identical. The first has a type that is the element type of the body array, the second has type ptr-to-element-type. Read your C book again :-)
Coverity tries to tell you that you make the same error as in
char foo[42];
/* write a string to foo */
bar = malloc (strlen(foo + 1)); /* which is strlen(&foo[1]) */
when the correct code is
bar = malloc (strlen(foo) + 1);
I think you misunderstood the paranthesis.
The + 1 in the coverity suggestion is outside the strlen(...)
I think coverity gets worried because you want to take strlen from index 1 instead of index 0. Coverity would expect index 0 as starting point - like:
body = malloc(strlen(&((my_type*) *my_variable)->Param2.body[0]) +1);
^
which is also
body = malloc(strlen(((my_type*) *my_variable)->Param2.body) +1);
^ ^
No & operator No [0]
as suggested by coverity
I have reached that conclusion #rici was correct. Considering the following simulation:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Param2{
char* body;
}Param2;
int main()
{
Param2 test;
test.body = "test_string\0";
printf("%s, size: %d + 1 terminating null\n\n",test.body, strlen(test.body));
printf("original: %d \n", (strlen(&test.body[1]) + 1));
printf("what coverity thinks: %d \n", strlen(test.body + 1));
printf("what coverity suggests: %d \n", (strlen(test.body) + 1));
printf("a more transparent way: %d \n\n", (strlen(test.body + 1) + 1));
return 1;
}
This is the output:
There are three cases (4th is the same as 1st). The allocated memory can be seen on the image above for all cases. Now, if we want to copy the source string from the 2. byte (&body[1]), that would mean 10 bytes of data in the example. And according to the strcpy documentation:
To avoid overflows, the size of the array pointed by destination shall
be long enough to contain the same C string as source (including the
terminating null character), and should not overlap in memory with
source.
We need one more for the null termination giving us 11 bytes to be allocated. Coverity believes that we are allocating 10 bytes, and suggest to allocate 12.
But as we can see, the original code allocates 11 bytes which is the exact number of bytes we need here, making the coverity deflect false positive.

Resources