0
votes

Scenario:
I am trying to validate some user-input. In my case the user is only allowed to enter between 0 and 3 lowercase characters, optionally including whitespace. In Regex: ^[a-z ]{0,3}$
If the user enters more than 3 characters or the input string contains invalid values, in each case a different return-value and error message has to be printed.

What I tried is to read the input into a temporary char array and defining the scanset as 4[a-z ], so that only the correct characters will be read and one char more, in order to check if the maximal number of desired characters has been read. I.e. if the last element in this temporary array is not empty the user input was bigger than 3.

Problem:
When the user enters 3 correct chars and a 4th wrong char, the 4th won't be read, therefore we read 3 valid chars, we "allegedly" never read an invalid char and the length of read chars is also valid, all tough it of course is not!

Code:

//--------------------------------------
int scan_input(char* char_array)
{
  int status = 0;
  int max_size = 3;
  char temp_array[max_size+1];

  // Print system prompt:
  printf("plain text: ");
  // Read user input:
  status = scanf("%4[a-z ]", temp_array);

  if (temp_array[max_size] != '\0')
  {
    printf("[ERR] too many characters\n");
    return -1;
  }

  if (status != 1)
  {
    printf("[ERR] invalid characters\n");
    return -2;
  }

  strcpy(char_array,temp_array);
  printf("[OK]  Input is valid!\n");
  return 0;
}

Output:

$ gcc -Wall -std=c11 application.c && ./a.out 
plain text: abcD
[OK]  Input is valid!

I am grateful for every hint to fix this blind spot!

PS.: If you know a better approach to solve this problem, than by doing it with scanf() and the scanset, your thoughts are welcome!

1
you have a buffer overflow. With input "abcD", scanf will write 'a', 'b', 'c', and 'D' to all elements of temp_array ... and it will (attempt to) write the terminating '\0' outside the array (overwriting some variable, rendering tests inconclusive, singing the national anthem, ...)pmg

1 Answers

1
votes

to validate some user-input

Separate the input from the parsing

  • Use a wide buffer and fgets().

    char buf[80];
    if (fgets(buf, sizeof buf, stdin)) {
      // we have some input
    
  • Then parse and use "%n", which records the scan position, to test success.

      int max_size = 3;
      char temp_array[max_size+1];
      int n = 0;
      temp_array[0] = '\0';
      sscanf(buf, "%3[a-z ]%n", temp_array, &n);
      bool success = buf[n] == '\n' || buf[n] == '\0';
    

If sscanf() did not scan anything, n == 0 and the prior temp_array[0] = 0 insures a null character.

If the scan succeeded, n > 0 and code inspects the next character.


Alternative staying with scanf()

status = scanf("%3[a-z ]", temp_array);

// When nothing read, form "" string   
if (status != 1) {
  temp_array[0] = '\0';
}

bool success = true;
if (status == EOF) {
  success = false;
} else {
  // consume rest of line, noting if extra junk followed
  int next_ch;
  while ((next_ch = fgetc(stdin)) != '\n' && next_ch != EOF) {
    success = false;  //Extra junk
  }
}