/** * NAME * strnlen_s * * SYNOPSIS * #include "safe_str_lib.h" * rsize_t * strnlen_s(const char *dest, rsize_t dmax) * * DESCRIPTION * The strnlen_s function computes the length of the string pointed * to by dest. * * SPECIFIED IN * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax restricted maximum length. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * dest shall not be a null pointer * dmax shall not be greater than RSIZE_MAX_STR * dmax shall not equal zero * * RETURN VALUE * The function returns the string length, excluding the terminating * null character. If dest is NULL, then strnlen_s returns 0. * * Otherwise, the strnlen_s function returns the number of characters * that precede the terminating null character. If there is no null * character in the first dmax characters of dest then strnlen_s returns * dmax. At most the first dmax characters of dest are accessed * by strnlen_s. * * ALSO SEE * strnterminate_s() * */ rsize_t strnlen_s (const char *dest, rsize_t dmax) { rsize_t count; if (dest == NULL) { return RCNEGATE(0); } if (dmax == 0) { invoke_safe_str_constraint_handler("strnlen_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(0); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strnlen_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(0); } count = 0; while (*dest && dmax) { count++; dmax--; dest++; } return RCNEGATE(count); }
/** * NAME * memzero16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memzero16_s(uint16_t *dest, rsize_t len) * * DESCRIPTION * Zeros len uint16_ts starting at dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to be zeroed. * * len number of uint16_ts to be zeroed * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * dest shall not be a null pointer. * len shall not be 0 nor greater than RSIZE_MAX_MEM16. * If there is a runtime constraint, the operation is not performed. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memzero_s(), memzero32_s() * */ errno_t memzero16_s (uint16_t *dest, rsize_t len) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memzero16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (len == 0) { invoke_safe_mem_constraint_handler("memzero16_s: len is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (len > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memzero16_s: len exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * mem_prim_set16(dest, len, 0xDEAD); * mem_prim_set16(dest, len, 0xBEEF); */ mem_prim_set16(dest, len, 0); return (RCNEGATE(EOK)); }
/** * NAME * memcpy16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcpy16_s(uint16_t *dest, rsize_t dmax, * const uint16_t *src, rsize_t smax) * * DESCRIPTION * This function copies at most smax uint16_ts from src to dest, up to * dmax. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be replaced by src. * * dmax maximum length of the resulting dest * * src pointer to the memory that will be copied to dest * * smax maximum number uint16_t of src to copy * * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM16. * smax shall not be greater than dmax. * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, the memcpy_s function stores * zeros in the first dmax bytes of the object pointed to by dest * if dest is not a null pointer and smax is valid. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP source memory overlaps destination * * ALSO SEE * memcpy_s(), memcpy32_s(), memmove_s(), memmove16_s(), memmove32_s() * */ errno_t memcpy16_s (uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t smax) { if (dest == NULL) { invoke_safe_mem_constraint_handler("memcpy16_s: dest is NULL", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcpy16_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memcpy16_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (src == NULL) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: src is NULL", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * overlap is undefined behavior, do not allow */ if( ((dest > src) && (dest < (src+smax))) || ((src > dest) && (src < (dest+dmax))) ) { mem_prim_set16(dest, dmax, 0); invoke_safe_mem_constraint_handler("memcpy16_s: overlap undefined", NULL, ESOVRLP); return (RCNEGATE(ESOVRLP)); } /* * now perform the copy */ mem_prim_move16(dest, src, smax); return (RCNEGATE(EOK)); }
/** * NAME * memmove16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memmove16_s(uint16_t *dest, rsize_t dmax, * const uint16_t *src, rsize_t smax) * * DESCRIPTION * The memmove16_s function copies smax uint16_t from the region * pointed to by src into the region pointed to by dest. This * copying takes place as if the smax uint16_t from the region * pointed to by src are first copied into a temporary array of * smax uint16_t that does not overlap the regions pointed to * by dest or src, and then the smax uint16_t from the temporary * array are copied into the region pointed to by dest. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to the memory that will be replaced by src. * * dmax maximum length of the resulting dest, in uint16_t * * src pointer to the memory that will be copied * to dest * * smax maximum number uint16_t of src that can be copied * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be 0. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * If there is a runtime-constraint violation, the memmove_s function * stores zeros in the first dmax characters of the regionpointed to * by dest if dest is not a null pointer and dmax is not greater * than RSIZE_MAX_MEM. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memmove_s(), memmove32_s(), memcpy_s(), memcpy16_s() memcpy32_s() * */ errno_t memmove16_s (uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t smax) { uint16_t *dp; const uint16_t *sp; dp= dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("memove16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memove16_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memove16_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { mem_prim_set16(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove16_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { mem_prim_set16(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove16_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (sp == NULL) { mem_prim_set16(dp, dmax, 0); invoke_safe_mem_constraint_handler("memove16_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } /* * now perform the copy */ mem_prim_move16(dp, sp, smax); return (RCNEGATE(EOK)); }
/** * NAME * memcpy_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcpy_s(void *dest, rsize_t dmax, const void *src, rsize_t smax) * * DESCRIPTION * This function copies at most smax bytes from src to dest, up to * dmax. The size values are unsigned values. * * AR: Dave - verify ISO spec requires unsigned * * SPECIFIED IN * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory that will be replaced by src. * * dmax maximum length of the resulting dest * * src pointer to the memory that will be copied to dest * * smax maximum number bytes of src to copy * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * Copying shall not take place between regions that overlap. * If there is a runtime-constraint violation, the memcpy_s function * stores zeros in the first dmax bytes of the region pointed to * by dest if dest is not a null pointer and smax is valid. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP source memory overlaps destination * * ALSO SEE * memcpy16_s(), memcpy32_s(), memmove_s(), memmove16_s(), * memmove32_s() * */ errno_t memcpy_s (void *dest, rsize_t dmax, const void *src, rsize_t smax) { uint8_t *dp; const uint8_t *sp; dp = dest; sp = src; if (dp == NULL) { invoke_safe_mem_constraint_handler("memcpy_s: dest is NULL", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_MEM) { invoke_safe_mem_constraint_handler("memcpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } // AR: This is not a requirement according to the ISO spec - Change? // AR: documentation needed on use of the error handlers - // AR: default err handler should output to stderr on DEBUG // AR: update docs to define return RCNEGATE of the error number if (smax == 0) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: smax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (smax > dmax) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: smax exceeds dmax", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (sp == NULL) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: src is NULL", NULL, ESNULLP); return RCNEGATE(ESNULLP); } /* * overlap is undefined behavior, do not allow */ if( ((dp > sp) && (dp < (sp+smax))) || ((sp > dp) && (sp < (dp+dmax))) ) { mem_prim_set(dp, dmax, 0); invoke_safe_mem_constraint_handler("memcpy_s: overlap undefined", NULL, ESOVRLP); return RCNEGATE(ESOVRLP); } /* * now perform the copy */ mem_prim_move(dp, sp, smax); return RCNEGATE(EOK); }
/* * NAME * strncpy_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t slen) * * DESCRIPTION * The strncpy_s function copies not more than slen successive characters * (characters that follow a null character are not copied) from the * array pointed to by src to the array pointed to by dest. If no null * character was copied from src, then dest[n] is set to a null character. * * All elements following the terminating null character (if any) * written by strncpy_s in the array of dmax characters pointed to * by dest take on the null value when strncpy_s returns. * * Specicified in: * ISO/IEC TR 24731-1, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * The resulting string is null terminated. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be copied * to string dest * * slen the maximum number of characters to copy from src * * OUTPUT PARAMETERS * dest updated with src string * * RUNTIME CONSTRAINTS * Neither dmax nor slen shall be equal to zero. * Neither dmax nor slen shall be equal zero. * Neither dmax nor slen shall be greater than RSIZE_MAX_STR. * If slen is either greater than or equal to dmax, then dmax * should be more than strnlen_s(src,dmax) * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and dmax greater than RSIZE_MAX_STR, * then strncpy_s nulls dest. * * RETURN VALUE * EOK successful operation, the characters in src were copied * to dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * ALSO SEE * strcat_s(), strncat_s(), strcpy_s() *- */ errno_t strncpy_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strncpy_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strncpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strncpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (src == NULL) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "src is null", ESNULLP); return RCNEGATE(ESNULLP); } if (slen == 0) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "slen is zero", ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "slen exceeds max", ESLEMAX); return RCNEGATE(ESLEMAX); } if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } if (slen == 0) { /* * Copying truncated to slen chars. Note that the TR says to * copy slen chars plus the null char. We null the slack. */ #ifdef SAFECLIB_STR_NULL_SLACK while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } if (slen == 0) { /* * Copying truncated to slen chars. Note that the TR says to * copy slen chars plus the null char. We null the slack. */ #ifdef SAFECLIB_STR_NULL_SLACK while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } /* * the entire src was not copied, so zero the string */ handle_error(orig_dest, orig_dmax, "strncpy_s: not enough " "space for src", ESNOSPC); return RCNEGATE(ESNOSPC); }
/** * NAME * strspn_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strspn_s(const char *dest, rsize_t dmax, * const char *src, rsize_t slen, rsize_t *count) * * DESCRIPTION * This function computes the prefix length of the string * pointed to by dest which consists entirely of characters * that are included from the string pointed to by src. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string to determine the prefix * * dmax restricted maximum length of string dest * * src pointer to exclusion string * * slen restricted maximum length of string src * * count pointer to a count variable that will be updated * with the dest substring length * * OUTPUT PARAMETERS * count updated count * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * count shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * EOK count * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strcspn_s(), strpbrk_s(), strstr_s(), strprefix_s() * */ errno_t strspn_s (const char *dest, rsize_t dmax, const char *src, rsize_t slen, rsize_t *count) { const char *scan2; rsize_t smax; bool match_found; if (count== NULL) { invoke_safe_str_constraint_handler("strspn_s: count is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *count = 0; if (dest == NULL) { invoke_safe_str_constraint_handler("strspn_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strspn_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strspn_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strspn_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (slen == 0 ) { invoke_safe_str_constraint_handler("strspn_s: slen is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strspn_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } while (*dest && dmax) { /* * Scan the entire src string for each dest character, counting * inclusions. */ match_found = false; smax = slen; scan2 = src; while (*scan2 && smax) { if (*dest == *scan2) { match_found = true; break; } scan2++; smax--; } if (match_found) { (*count)++; } else { break; } dest++; dmax--; } return RCNEGATE(EOK); }
/** * NAME * strpbrk_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strpbrk_s(char *dest, rsize_t dmax, * char *src, rsize_t slen, char **first) * * DESCRIPTION * Returns a pointer, first, to the first ocurrence of any character * in src which is contained in dest. * * EXTENSION TO * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string * * dmax restricted maximum length of string dest * * src pointer to string * * slen restricted length of string src * * first returned pointer to first occurence * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * first shall not be a null pointer. * dmax shall not be 0 * dmax shall not be greater than RSIZE_MAX_STR * * RETURN VALUE * pointer to the first ocurrence of any character * contained in src * * EOK count * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * strfirstchar_s(), strlastchar_s(), strfirstdiff_s(), * strfirstsame_s(), strlastdiff_s(), strlastsame_s() * */ errno_t strpbrk_s (char *dest, rsize_t dmax, char *src, rsize_t slen, char **first) { char *ps; rsize_t len; if (first == NULL) { invoke_safe_str_constraint_handler("strpbrk_s: count is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } *first = NULL; if (dest == NULL) { invoke_safe_str_constraint_handler("strpbrk_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strpbrk_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0 ) { invoke_safe_str_constraint_handler("strpbrk_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strpbrk_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (slen == 0 ) { invoke_safe_str_constraint_handler("strpbrk_s: slen is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strpbrk_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* * look for a matching char in the substring src */ while (*dest && dmax) { ps = src; len = slen; while (*ps) { /* check for a match with the substring */ if (*dest == *ps) { *first = dest; return RCNEGATE(EOK); } ps++; len--; } dest++; dmax--; } return RCNEGATE(ESNOTFND); }
/** * NAME * strcpy_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strcpy_s(char *dest, rsize_t dmax, const char *src) * * DESCRIPTION * The strcpy_s function copies the string pointed to by src * (including the terminating null character) into the array * pointed to by dest. All elements following the terminating * null character (if any) written by strcpy_s in the array * of dmax characters pointed to by dest are nulled when * strcpy_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be replaced by src. * * dmax restricted maximum length of dest * * src pointer to the string that will be copied * to dest * * OUTPUT PARAMETERS * dest updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * dmax shall not be greater than RSIZE_MAX_STR. * dmax shall not equal zero. * dmax shall be greater than strnlen_s(src, dmax). * Copying shall not take place between objects that overlap. * If there is a runtime-constraint violation, then if dest * is not a null pointer and destmax is greater than zero and * not greater than RSIZE_MAX_STR, then strcpy_s nulls dest. * * RETURN VALUE * EOK successful operation, the characters in src were * copied into dest and the result is null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESOVRLP strings overlap * ESNOSPC not enough space to copy src * * ALSO SEE * strcat_s(), strncat_s(), strncpy_s() * */ errno_t strcpy_s (char *dest, rsize_t dmax, const char *src) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strcpy_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("strcpy_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strcpy_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (src == NULL) { #ifdef SAFECLIB_STR_NULL_SLACK /* null string to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif invoke_safe_str_constraint_handler("strcpy_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dest == src) { return RCNEGATE(EOK); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } else { overlap_bumper = dest; while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strcpy_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } /* * the entire src must have been copied, if not reset dest * to null the string. */ handle_error(orig_dest, orig_dmax, "strcpy_s: not " "enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); }
/** * NAME * memcmp16_s * * SYNOPSIS * #include "safe_mem_lib.h" * errno_t * memcmp16_s(const uint16_t *dest, rsize_t dmax, * const uint16_t *src, rsize_t smax, int *diff) * * DESCRIPTION * Compares memory until they differ, and their difference is * returned in diff. If the block of memory is the same, diff=0. * * EXTENSION TO * ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to memory to compare against * * dmax maximum length of dest, in uint16_t * * src pointer to the source memory to compare with dest * * smax maximum length of src, in uint16_t * * *diff pointer to the diff which is an integer greater * than, equal to or less than zero according to * whether the object pointed to by dest is * greater than, equal to or less than the object * pointed to by src. * * OUTPUT PARAMETERS * none * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer. * Neither dmax nor smax shall be zero. * dmax shall not be greater than RSIZE_MAX_MEM. * smax shall not be greater than dmax. * * RETURN VALUE * EOK successful operation * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * * ALSO SEE * memcmp_s(), memcmp32_s() * */ errno_t memcmp16_s (const uint16_t *dest, rsize_t dmax, const uint16_t *src, rsize_t smax, int *diff) { const uint16_t *dp; const uint16_t *sp; dp = dest; sp = src; /* * must be able to return the diff */ if (diff == NULL) { invoke_safe_mem_constraint_handler("memcmp16_s: diff is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } *diff = -1; /* default diff */ if (dp == NULL) { invoke_safe_mem_constraint_handler("memcmp16_s: dest is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (sp == NULL) { invoke_safe_mem_constraint_handler("memcmp16_s: src is null", NULL, ESNULLP); return (RCNEGATE(ESNULLP)); } if (dmax == 0) { invoke_safe_mem_constraint_handler("memcmp16_s: dmax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (dmax > RSIZE_MAX_MEM16) { invoke_safe_mem_constraint_handler("memcmp16_s: dmax exceeds max", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } if (smax == 0) { invoke_safe_mem_constraint_handler("memcmp16_s: smax is 0", NULL, ESZEROL); return (RCNEGATE(ESZEROL)); } if (smax > dmax) { invoke_safe_mem_constraint_handler("memcmp16_s: smax exceeds dmax", NULL, ESLEMAX); return (RCNEGATE(ESLEMAX)); } /* * no need to compare the same memory */ if (dp == sp) { *diff = 0; return (RCNEGATE(EOK)); } /* * now compare sp to dp */ *diff = 0; while (dmax != 0 && smax != 0) { if (*dp != *sp) { *diff = *dp - *sp; break; } dmax--; smax--; dp++; sp++; } return (RCNEGATE(EOK)); }
/** * NAME * strncat_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * strncat_s(char *dest, rsize_t dmax, const char *src, rsize_t slen) * * DESCRIPTION * The strncat_s function appends a copy of the string pointed * to by src (including the terminating null character) to the * end of the string pointed to by dest. The initial character * from src overwrites the null character at the end of dest. * * All elements following the terminating null character (if * any) written by strncat_s in the array of dmax characters * pointed to by dest take unspecified values when strncat_s returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to string that will be extended by src * if dmax allows. The string is null terminated. * If the resulting concatenated string is less * than dmax, the remaining slack space is nulled. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be concatenaed * to string dest * * slen maximum characters to append * * OUTPUT PARAMETERS * dest updated string * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer * dmax shall not equal zero * dmax shall not be greater than RSIZE_STR_MAX * dmax shall be greater than strnlen_s(src,m). * Copying shall not takeplace between objects that overlap * If there is a runtime-constraint violation, then if dest is * not a null pointer and dmax is greater than zero and not * greater thanRSIZE_MAX, then strncat_s sets dest[0] to the * null character. * * RETURN VALUE * EOK successful operation, all the characters from src * were appended to dest and the result in dest is * null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max limit * ESUNTERM dest not terminated * * */ errno_t strncat_s (char *dest, rsize_t dmax, const char *src, rsize_t slen) { rsize_t orig_dmax; char *orig_dest; const char *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("strncat_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("strncat_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (slen > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strncat_s: slen exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } if (dmax == 0) { invoke_safe_str_constraint_handler("strncat_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("strncat_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; /* Find the end of dest */ while (*dest != '\0') { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } dest++; dmax--; if (dmax == 0) { handle_error(orig_dest, orig_dmax, "strncat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (dest == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } /* * Copying truncated before the source null is encountered */ if (slen == 0) { #ifdef SAFECLIB_STR_NULL_SLACK /* null remaining string */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } else { overlap_bumper = dest; /* Find the end of dest */ while (*dest != '\0') { /* * NOTE: no need to check for overlap here since src comes first * in memory and we're not incrementing src here. */ dest++; dmax--; if (dmax == 0) { handle_error(orig_dest, orig_dmax, "strncat_s: " "dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (src == overlap_bumper) { handle_error(orig_dest, orig_dmax, "strncat_s: " "overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } /* * Copying truncated */ if (slen == 0) { #ifdef SAFECLIB_STR_NULL_SLACK /* null remaining string */ while (dmax) { *dest = '\0'; dmax--; dest++; } #else *dest = '\0'; #endif return RCNEGATE(EOK); } *dest = *src; if (*dest == '\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = '\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; slen--; dest++; src++; } } /* * the entire src was not copied, so the string will be nulled. */ handle_error(orig_dest, orig_dmax, "strncat_s: not enough " "space for src", ESNOSPC); return RCNEGATE(ESNOSPC); }
/** * NAME * wcscat_s * * SYNOPSIS * #include "safe_str_lib.h" * errno_t * wcscat_s(wchar_t* dest, rsize_t dmax, const wchar_t* src) * * DESCRIPTION * The wcscat_s function appends a copy of the wide characer string pointed * to by src (including the terminating null character) to the * end of the string pointed to by dest. The initial wide character * from src overwrites the null character at the end of dest. * * All elements following the terminating null character (if * any) written by strcat_s in the array of dmax characters * pointed to by dest take unspecified values when strcat_s * returns. * * SPECIFIED IN * ISO/IEC TR 24731, Programming languages, environments * and system software interfaces, Extensions to the C Library, * Part I: Bounds-checking interfaces * * INPUT PARAMETERS * dest pointer to wide character string that will be extended by src * if dmax allows. The string is null terminated. * If the resulting concatenated string is less * than dmax, the remaining slack space is nulled. * * dmax restricted maximum length of the resulting dest, * including the null * * src pointer to the string that will be concatenaed * to string dest * * OUTPUT PARAMETERS * dest is updated * * RUNTIME CONSTRAINTS * Neither dest nor src shall be a null pointer * dmax shall not equal zero * dmax shall not be greater than RSIZE_MAX_STR * dmax shall be greater than strnlen_s(src,m). * Copying shall not takeplace between objects that overlap * If there is a runtime-constraint violation, then if dest is * not a null pointer and dmax is greater than zero and not * greater than RSIZE_MAX_STR, then strcat_s nulls dest. * * RETURN VALUE * EOK successful operation, all the characters from src * were appended to dest and the result in dest is * null terminated. * ESNULLP NULL pointer * ESZEROL zero length * ESLEMAX length exceeds max * ESUNTERM dest not terminated * * ALSO SEE * strcat_s, strncat_s(), strcpy_s(), strncpy_s() * */ errno_t wcscat_s(wchar_t* dest, rsize_t dmax, const wchar_t* src) { rsize_t orig_dmax; wchar_t *orig_dest; const wchar_t *overlap_bumper; if (dest == NULL) { invoke_safe_str_constraint_handler("wcscat_s: dest is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (src == NULL) { invoke_safe_str_constraint_handler("wcscat_s: src is null", NULL, ESNULLP); return RCNEGATE(ESNULLP); } if (dmax == 0) { invoke_safe_str_constraint_handler("wcscat_s: dmax is 0", NULL, ESZEROL); return RCNEGATE(ESZEROL); } if (dmax*sizeof(wchar_t) > RSIZE_MAX_STR) { invoke_safe_str_constraint_handler("wcscat_s: dmax exceeds max", NULL, ESLEMAX); return RCNEGATE(ESLEMAX); } /* hold base of dest in case src was not copied */ orig_dmax = dmax; orig_dest = dest; if (dest < src) { overlap_bumper = src; /* Find the end of dest */ while (*dest != L'\0') { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } dest++; dmax--; if (dmax == 0) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (dest == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } else { overlap_bumper = dest; /* Find the end of dest */ while (*dest != L'\0') { /* * NOTE: no need to check for overlap here since src comes first * in memory and we're not incrementing src here. */ dest++; dmax--; if (dmax == 0) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: dest unterminated", ESUNTERM); return RCNEGATE(ESUNTERM); } } while (dmax > 0) { if (src == overlap_bumper) { handle_wc_error(orig_dest, orig_dmax, "wcscat_s: overlapping objects", ESOVRLP); return RCNEGATE(ESOVRLP); } *dest = *src; if (*dest == L'\0') { #ifdef SAFECLIB_STR_NULL_SLACK /* null slack to clear any data */ while (dmax) { *dest = L'\0'; dmax--; dest++; } #endif return RCNEGATE(EOK); } dmax--; dest++; src++; } } /* * the entire src was not copied, so null the string */ handle_wc_error(orig_dest, orig_dmax, "wcscat_s: not enough space for src", ESNOSPC); return RCNEGATE(ESNOSPC); }