Reputation: 361
In C language I have a uint8_t
array and, after some logic, I need to cast to string and check if contains some substring like this:
uint8_t data[8] = {0xcb,0xe2,0x3d,0x96,0x55,0xfc,0xcd,0x43};
/// some logic
if(strstr((const char *)data, "000") != NULL){
}
Is if statement correct? it seems to return always true.
Upvotes: 3
Views: 108
Reputation: 213960
All functions prefixed with str
in the C standard library assume that you pass a null terminated string to them. If you pass something else, like in this case, you invoke undefined behavior and will get crashes or wrong results etc.
We could cook up our own (naive) function for this easily enough by iterating across the data and comparing it to the search key string with memcmp
:
#include <string.h>
#include <stdint.h>
const uint8_t* memstr (const uint8_t* data, const char* key, size_t size)
{
const uint8_t* result = NULL;
size_t key_length = strlen(key);
for(size_t i=0; i<size-key_length+1; i++)
{
if(memcmp(&data[i], key, key_length) == 0)
{
result = &data[i];
break;
}
}
return result;
}
Here the requirement is that key
is a null terminated string but data
could be anything. Since key
is a string we can call strlen
on it. We should only iterate up to the buffer size minus key length amount of bytes. So for example with 8 data bytes and a search key of "000"
thats 8-3=5 bytes. But we have to check data indices 0 to 5, so a +1 on the loop condition is needed.
Complete test code:
#include <string.h>
#include <stdint.h>
#include <stdio.h>
const uint8_t* memstr (const uint8_t* data, const char* key, size_t size)
{
const uint8_t* result = NULL;
size_t key_length = strlen(key);
for(size_t i=0; i<size-key_length+1; i++)
{
if(memcmp(&data[i], key, key_length) == 0)
{
result = &data[i];
break;
}
}
return result;
}
#define test_memstr(data, key) \
found = memstr(data, key, sizeof data); \
if(found) \
printf("\"%.*s\" found at index %tu\n", \
strlen(key), found, found-data); \
else \
puts("Not found");
int main (void)
{
uint8_t data1[8] = {0xcb,0xe2,0x3d,0x96,0x55,0xfc,0xcd,0x43};
uint8_t data2[11] = {0x48,0x65,0x6C,0x6C,0x6F,0x20,0x57,0x6F,0x72,0x6C,0x64};
const uint8_t* found;
test_memstr(data1, "000");
test_memstr(data2, "World");
test_memstr(data2, "Hello");
}
Upvotes: 1
Reputation: 28094
As you can see in the strstr
documentation, the first argument is:
str - pointer to the null-terminated byte string to examine
(emphasis is mine)
In your case data
which is passed as an arugment for str
is not null-terminated.
The documentation also states that:
The behavior is undefined if either str or substr is not a pointer to a null-terminated byte string.
Your code therefore invokes undefined-bahevior, meaning the standard does not guarantee the result and it's possible that the function will always return true
(as well as any other behavior).
A possible solution is to make data
9 bytes and add 0x00
, making it null-terminated.
Another solution (as @ChrisDodd commented) is applicable if you are using GNU libc:
Use memmem
function. It works similarly to strstr
, but accepts buffers length and does not require null-termination.
Upvotes: 5