Guest User

Untitled

a guest
Oct 27th, 2020
30
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Compile with gcc -Wall -Wextra -pedantic -std=c17 -D_POSIX_C_SOURCE=2
  2.  
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. #include <string.h>
  6. #include <assert.h>
  7. #include <stdlib.h>
  8.  
  9. // Counts the number of assignments that should be made by scanf and alike.
  10. // Assumes a valid format string. If it's not valid, behavior is undefined.
  11.  
  12. int count_assignments(const char *fmt) {
  13. int ret = 0;
  14.  
  15. // Note that n is removed, because it suppresses assignments
  16. static const char specifiers[] = "diouxaefgcspAEFGX";
  17. static const char singlelength[] = "hljztL";
  18. static const char doublelength[] = "hl";
  19.  
  20. while(*fmt) {
  21. if(*fmt == '%') {
  22. fmt++;
  23.  
  24. // Skip width modification
  25. while(isdigit(*fmt)) fmt++;
  26.  
  27. // Check length modification
  28. if(strchr(singlelength, *fmt)) {
  29. fmt++;
  30. if(strchr(doublelength, *fmt)) {
  31. fmt++;
  32. goto READ_SPECIFIER;
  33. }
  34. goto READ_SPECIFIER;
  35. }
  36. if(*fmt == '[') {
  37. while(*fmt != ']') fmt++;
  38. ret++;
  39. goto END;
  40. }
  41. goto READ_SPECIFIER;
  42. }
  43.  
  44. goto END;
  45.  
  46. READ_SPECIFIER:
  47. if(strchr(specifiers, *fmt))
  48. ret++;
  49. END:
  50. fmt++;
  51. }
  52.  
  53. return ret;
  54. }
  55.  
  56. // Calculate how many arguments a format string should have by creating a .c file which
  57. // is compiled and the number of warnings are counted. This value is treated as the number
  58. // of arguments the format strings wants.
  59. size_t get_no_warnings(const char *fmt)
  60. {
  61. FILE *fp = fopen("warning.c", "w");
  62. if(!fp) {
  63. perror("Error opening file");
  64. exit(EXIT_FAILURE);
  65. }
  66.  
  67. fprintf(fp, "#include <stdio.h>\n\nint main(void) {\n\tscanf(\"%s\");\n}\n", fmt);
  68. fclose(fp);
  69.  
  70. fp = popen("gcc warning.c -Wall -Wextra -pedantic 2>&1 | grep \"warning: format\" | wc -l", "r");
  71.  
  72. if(!fp) {
  73. perror("Error executing command");
  74. exit(EXIT_FAILURE);
  75. }
  76.  
  77. char output[100];
  78. fgets(output, sizeof(output), fp);
  79. size_t ret;
  80. if(sscanf(output, "%zu", &ret) != 1) {
  81. perror("Error reading output");
  82. exit(EXIT_FAILURE);
  83. }
  84. return ret;
  85. }
  86.  
  87. int main(void)
  88. {
  89. struct test_case {
  90. const char *fmt;
  91. const unsigned n;
  92. } test_cases[] = {
  93. { "foo", 0 },
  94. { "%s", 1 },
  95. { "%d%d", 2 },
  96. { "%lld", 1 },
  97. { "%%", 0 },
  98. { "%d%%%d", 2 },
  99. { "%2333d%c%33f", 3 },
  100. { "%[bar]", 1 },
  101. { "%*d", 0 },
  102. { "%*22d", 0 },
  103. { "%d%p%c", 3 }
  104. };
  105.  
  106. for(size_t i=0; i<sizeof test_cases/sizeof test_cases[0]; i++) {
  107. struct test_case tc = test_cases[i];
  108. size_t count = count_assignments(tc.fmt);
  109. size_t warnings = get_no_warnings(tc.fmt);
  110. printf("%s %u %zu %zu\n", tc.fmt, tc.n, count, warnings);
  111. assert(count == tc.n);
  112. assert(count == warnings);
  113. }
  114. }
  115.  
RAW Paste Data