@ @ requires \valid_read((const char *)haystack+(0..haystack_len-1)); @ requires \valid_read((const char *)needle+(0..needle_len-1)); @ assigns \nothing; @ ensures result_null_or_in_haystack: @ \result == \null @ || (\subset((char *)\result, (char *)haystack+(0..haystack_len-needle_len)) && \valid_read((char *)\result)); @*/
| 33 | @ || (\subset((char *)\result, (char *)haystack+(0..haystack_len-needle_len)) && \valid_read((char *)\result)); |
| 34 | @*/ |
| 35 | static inline const void *td_memmem(const void *haystack, const unsigned int haystack_len, const void *needle, const unsigned int needle_len) |
| 36 | { |
| 37 | const char *begin; |
| 38 | const char *const last_possible = (const char *) haystack + haystack_len - needle_len; |
| 39 | |
| 40 | if (needle_len == 0) |
| 41 | /* The first occurrence of the empty string is deemed to occur at |
| 42 | the beginning of the string. */ |
| 43 | /*@ assert (\subset((char *)haystack, (char *)haystack+(0..haystack_len-needle_len)) && \valid_read((char *)haystack)); */ |
| 44 | return (const void *) haystack; |
| 45 | |
| 46 | /* Sanity check, otherwise the loop might search through the whole |
| 47 | memory. */ |
| 48 | if (haystack_len < needle_len) |
| 49 | return NULL; |
| 50 | |
| 51 | /*@ |
| 52 | @ loop invariant \valid_read(begin); |
| 53 | @ loop invariant \subset(begin, (char *)haystack+(0..haystack_len-needle_len+1)); |
| 54 | @ loop assigns begin; |
| 55 | @*/ |
| 56 | for (begin = (const char *) haystack; begin <= last_possible; ++begin) |
| 57 | { |
| 58 | if (begin[0] == ((const char *) needle)[0] && |
| 59 | !memcmp ((const void *) &begin[1], |
| 60 | (const void *) ((const char *) needle + 1), |
| 61 | needle_len - 1)) |
| 62 | { |
| 63 | /*@ assert (\subset(begin, (char *)haystack+(0..haystack_len-needle_len)) && \valid_read(begin)); */ |
| 64 | return (const void *) begin; |
| 65 | } |
| 66 | } |
| 67 | return NULL; |
| 68 | } |
| 69 | #endif |
no outgoing calls
no test coverage detected