Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added another CS

...

However, if the last character in buf is not a newline and the stream is not at the end-of-file marker, the buffer was too small to contain all of the data from the user.  For example, because the buffer is only 8 characters in length, if the user input "Hello World\n", the buffer would contain "Hello W" terminated by a null character.

Compliant Solution (Fail on Truncation)

This compliant solution examines the end-of-file marker for the stream and the last character in the buffer to determine whether it is a newline or not.  If it is the end of file, or the last character is a newline, then the buffer contains all of the user's input.  However, if the last character is not at the end-of-file and not a newline then the user's input has been truncated.

Code Block
bgColor#ccccff
langc
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
 
bool get_data(char *buffer, int size) {
  if (fgets(buffer, size, stdin)) {
    size_t len = strlen(buffer);
    return feof(stdin) || (len != 0 && buffer[len-1] == '\n');
  }
  return false;
}
 
void func(void) {
  char buf[8];
  if (get_data(buf, sizeof(buf))) {
    printf("The user input %s\n", buf);
  } else {
    printf("Error getting data from the user\n");
  }
}

Compliant Solution (Expanding Buffer)

This compliant solution solves the problem by expanding the buffer to read the entire contents from stdin instead of failing if the caller did not allocate enough space.  If the allocation fails, it will return NULL, but otherwise, it returns a buffer of the received data, which the caller must free.

 

Code Block
bgColor#ccccff
langc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *get_filled_buffer(void) {
  char *ret = NULL;
  char *end = NULL;
  char temp[32];

  while (fgets(temp, sizeof(temp), stdin)) {
    size_t len = strlen(temp);
    const size_t full_size = end - ret + len;
    char *r_temp = realloc(ret, full_size + 1); /* NTBS */
    if (r_temp) {
      ret = r_temp;
      strcat(ret, temp);
      end = ret + full_size;
    } else {
      break;
    }

    if (feof(stdin) || temp[len] == '\n') {
      return ret;
    }
  }
  free(ret);
  return NULL;
}

Risk Assessment

Incorrectly assuming a newline character is read by fgets() or fgetws() can result in data truncation.

...