Alternatives to strnlen_s: Ensuring Safe String Length Determination in C


  • Return value

    • The function returns the length of the string excluding the null terminator, if a null terminator is found within the specified max_len characters.
    • If the string is null (null pointer) or the null terminator is not found within the limit, it returns 0.
  • Functionality

    1. Null pointer check
      The function first checks if the str_ptr (pointer to the string) is null. If it is, it immediately returns 0, indicating an invalid string.
    2. Iterate and count
      It starts iterating through the characters pointed to by str_ptr. It uses a counter variable to keep track of the number of characters encountered.
    3. Bounds check
      Within the loop, it checks two things for each character:
      • If the current character is the null terminator (\0). If it is, it means the string has ended, and the function returns the count of characters encountered so far (excluding the null terminator).
      • If the counter reaches the value of max_len. This indicates that the function has reached the maximum specified length without finding a null terminator. In this case, it treats the string as potentially truncated and returns 0 to signal an error condition.
    • str_ptr: This is a pointer to the character array that represents the string.
    • max_len: This is an integer value specifying the maximum number of characters to consider from the string.


#include <stdio.h>
#include <string.h> // for strnlen_s (requires C11 or later with appropriate extensions)

int main() {
  const char str1[] = "This is a string with null terminator";
  size_t max_len1 = sizeof(str1) - 1; // Exclude null terminator from max length
  size_t str1_len = strnlen_s(str1, max_len1);

  const char str2[] = "Potentially truncated string";
  size_t max_len2 = 10; // Consider only first 10 characters
  size_t str2_len = strnlen_s(str2, max_len2);

  printf("String 1 length (safe): %zu\n", str1_len);
  printf("String 2 length (limited to 10 characters): %zu\n", str2_len);

  // Example of potential error with strnlen (not recommended)
  // char str3[] = "Another string"; // No null terminator!
  // size_t str3_len = strnlen(str3, 15); // Undefined behavior!

  return 0;
}
  1. We include <stdio.h> for input/output functions and <string.h> for strnlen_s.
  2. We define two string arrays: str1 with a null terminator and str2 without one (for demonstration purposes).
  3. We calculate the safe maximum length for str1 by subtracting 1 from its size (to exclude the null terminator).
  4. We call strnlen_s for both strings with their respective maximum lengths.
  5. We print the safe lengths of str1 and str2.
  6. We comment out an example using strnlen on a string without a null terminator. This is not recommended as it can lead to undefined behavior and potential crashes.


    • If you're using a C compiler that supports C99 or later, you can use the standard strnlen function. It calculates the length of a string, but without the safety checks of strnlen_s.
    • To mitigate buffer overflow risks, you can combine strnlen with an explicit check for the null terminator within the specified max_len:
    size_t safe_strnlen(const char* str, size_t max_len) {
      size_t len = strnlen(str, max_len);
      if (len == max_len && str[len] != '\0') {
        // String potentially truncated, handle error
        return 0;
      }
      return len;
    }
    
  1. memchr function

    • The memchr function locates the first occurrence of a given character in a memory block. You can use it to find the null terminator within the specified max_len.
    • It returns a pointer to the null terminator if found within the limit, otherwise it returns NULL. The pointer difference with the original string pointer gives you the length.
    size_t safe_strnlen(const char* str, size_t max_len) {
      const char* null_char = memchr(str, '\0', max_len);
      if (null_char == NULL) {
        // String potentially truncated, handle error
        return 0;
      }
      return null_char - str;
    }
    
  2. Custom implementation

    • You can write your own function that iterates through the string, checks for the null terminator within the limit, and returns the count.