glsl-array-bounds: set out-of-bounds array index inside shader
[piglit.git] / tests / util / piglit-util.c
blob3a8f9bcfbce37db109bb19768ce7cf342c5a578e
1 /*
2 * Copyright (c) The Piglit project 2007
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #if defined(_WIN32)
25 #ifndef WIN32_LEAN_AND_MEAN
26 #define WIN32_LEAN_AND_MEAN
27 #endif
28 #include <windows.h>
29 #endif
31 #ifdef __linux__
32 #include <sys/types.h>
33 #include <sys/syscall.h>
34 #endif
36 #include <assert.h>
37 #include <math.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <inttypes.h>
43 #include <time.h>
45 #if defined(PIGLIT_HAS_POSIX_CLOCK_MONOTONIC) && defined(PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD)
46 #include <pthread.h>
47 #include <signal.h>
48 #endif
50 #include "config.h"
51 #if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_SETRLIMIT)
52 #include <sys/time.h>
53 #include <sys/resource.h>
54 #define USE_SETRLIMIT
55 #endif
57 #if defined(HAVE_FCNTL_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H) && defined(HAVE_UNISTD_H) && !defined(_WIN32)
58 # include <sys/types.h>
59 # include <sys/stat.h>
60 # include <fcntl.h>
61 # include <unistd.h>
62 #else
63 # define USE_STDIO
64 #endif
66 #if defined(HAVE_UNISTD_H)
67 #include <unistd.h> // for usleep
68 #endif
70 #include "piglit-util.h"
73 #ifndef HAVE_ASPRINTF
75 /* Some versions of MinGW are missing _vscprintf's declaration, although they
76 * still provide the symbol in the import library.
78 #ifdef __MINGW32__
79 _CRTIMP int _vscprintf(const char *format, va_list argptr);
80 #endif
82 int asprintf(char **strp, const char *fmt, ...)
84 va_list args;
85 va_list args_copy;
86 int length;
87 size_t size;
89 va_start(args, fmt);
91 va_copy(args_copy, args);
93 #ifdef _WIN32
94 /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1
95 * if the number of characters to write is greater than count.
97 length = _vscprintf(fmt, args_copy);
98 #else
99 char dummy;
100 length = vsnprintf(&dummy, sizeof dummy, fmt, args_copy);
101 #endif
103 va_end(args_copy);
105 assert(length >= 0);
106 size = length + 1;
108 *strp = malloc(size);
109 if (!*strp) {
110 return -1;
113 va_start(args, fmt);
114 vsnprintf(*strp, size, fmt, args);
115 va_end(args);
117 return length;
120 #endif /* HAVE_ASPRINTF */
123 * \brief Split \a string into an array of strings.
125 * The null-terminated string \a separators is a list of characters at
126 * which to perform the splits. For example, if separators is " ,", then
127 * the function will split the string at each occurence of ' ' and ','.
129 const char**
130 piglit_split_string_to_array(const char *string, const char *separators)
132 char **strings, *string_copy;
133 int i, length, max_words;
135 length = strlen(string);
136 max_words = length / 2;
137 strings = malloc((sizeof(char*) * (max_words + 1)) +
138 (sizeof(char) * (length + 1)));
139 assert(strings != NULL);
141 string_copy = (char*) &strings[max_words + 1];
142 strcpy(string_copy, string);
144 strings[0] = strtok(string_copy, separators);
145 for (i = 0; strings[i] != NULL; ++i) {
146 strings[i + 1] = strtok(NULL, separators);
149 return (const char**) strings;
152 bool piglit_is_extension_in_array(const char **haystack, const char *needle)
154 if (needle[0] == 0)
155 return false;
157 while (*haystack != NULL) {
158 if (strcmp(*haystack, needle) == 0) {
159 return true;
161 haystack++;
164 return false;
167 bool piglit_is_extension_in_string(const char *haystack, const char *needle)
169 const unsigned needle_len = strlen(needle);
171 if (needle_len == 0)
172 return false;
174 while (true) {
175 const char *const s = strstr(haystack, needle);
177 if (s == NULL)
178 return false;
180 if (s[needle_len] == ' ' || s[needle_len] == '\0') {
181 return true;
184 /* strstr found an extension whose name begins with
185 * needle, but whose name is not equal to needle.
186 * Restart the search at s + needle_len so that we
187 * don't just find the same extension again and go
188 * into an infinite loop.
190 haystack = s + needle_len;
193 return false;
196 /** Returns the line in the program string given the character position. */
197 int piglit_find_line(const char *program, int position)
199 int i, line = 1;
200 for (i = 0; i < position; i++) {
201 if (program[i] == '0')
202 return -1; /* unknown line */
203 if (program[i] == '\n')
204 line++;
206 return line;
209 const char *
210 piglit_result_to_string(enum piglit_result result)
212 switch (result) {
213 case PIGLIT_FAIL: return "fail";
214 case PIGLIT_SKIP: return "skip";
215 case PIGLIT_WARN: return "warn";
216 case PIGLIT_PASS: return "pass";
218 return "Unknown result";
221 void
222 piglit_report_result(enum piglit_result result)
224 const char *result_str = piglit_result_to_string(result);
226 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
227 /* Ensure we only report one result in case we race with timeout */
228 static pthread_mutex_t result_lock = PTHREAD_MUTEX_INITIALIZER;
229 pthread_mutex_lock(&result_lock);
230 #endif
232 fflush(stderr);
234 printf("PIGLIT: {\"result\": \"%s\" }\n", result_str);
235 fflush(stdout);
237 switch(result) {
238 case PIGLIT_PASS:
239 case PIGLIT_SKIP:
240 case PIGLIT_WARN:
241 exit(0);
242 default:
243 exit(1);
247 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
248 static void
249 timeout_expired(union sigval val)
251 piglit_loge("Test timed out.");
252 piglit_report_result(val.sival_int);
254 #endif
256 void
257 piglit_set_timeout(double seconds, enum piglit_result timeout_result)
259 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
260 struct sigevent sev = {
261 .sigev_notify = SIGEV_THREAD,
262 .sigev_notify_function = timeout_expired,
263 .sigev_value = { .sival_int = timeout_result },
265 time_t sec = seconds;
266 struct itimerspec spec = {
267 .it_value = { .tv_sec = sec, .tv_nsec = (seconds - sec) * 1e9 },
269 timer_t timerid;
270 timer_create(CLOCK_MONOTONIC, &sev, &timerid);
271 timer_settime(timerid, 0, &spec, NULL);
272 #else
273 piglit_logi("Cannot abort this test for timeout on this platform");
274 #endif
277 void
278 piglit_report_subtest_result(enum piglit_result result, const char *format, ...)
280 const char *result_str = piglit_result_to_string(result);
281 va_list ap;
283 va_start(ap, format);
285 printf("PIGLIT: {\"subtest\": {\"");
286 vprintf(format, ap);
287 printf("\" : \"%s\"}}\n", result_str);
288 fflush(stdout);
290 va_end(ap);
294 static void
295 piglit_disable_error_message_boxes(void)
297 /* When Windows' error message boxes are disabled for this process (as
298 * is always the case when running through `piglit run`) we disable CRT
299 * message boxes too.
301 * This will disable the CRT message boxes for the main executable, but
302 * it will not disable message boxes for assertion failures inside
303 * OpenGL ICD, unless this test's executable and the OpenGL ICD DLL are
304 * both dynamically linked to the same CRT DLL. If the OpenGL ICD is
305 * statically linked to the CRT then it must do these calls itself.
307 #ifdef _WIN32
308 UINT uMode;
309 #if _WIN32_WINNT >= 0x0600
310 uMode = GetErrorMode();
311 #else
312 uMode = SetErrorMode(0);
313 SetErrorMode(uMode);
314 #endif
315 if (uMode & SEM_FAILCRITICALERRORS) {
316 /* Disable assertion failure message box.
317 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
319 _set_error_mode(_OUT_TO_STDERR);
321 #endif /* _WIN32 */
325 static void
326 piglit_set_line_buffering(void)
328 /* Windows doesn't immediately flush stdout/stderr after printf
329 * calls as we see on Linux. To get immediate flushing, we disable
330 * buffering here.
332 #ifdef _WIN32
333 setbuf(stdout, NULL);
334 setbuf(stderr, NULL);
335 #endif
339 void
340 piglit_general_init(void)
342 piglit_disable_error_message_boxes();
343 piglit_set_line_buffering();
347 void
348 piglit_set_rlimit(unsigned long lim)
350 #if defined(USE_SETRLIMIT) && defined(RLIMIT_AS)
351 struct rlimit rl;
352 if (getrlimit(RLIMIT_AS, &rl) != -1) {
353 piglit_logi("Address space limit = %lu, max = %lu",
354 (unsigned long) rl.rlim_cur,
355 (unsigned long) rl.rlim_max);
357 if (rl.rlim_max > lim) {
358 piglit_logi("Resetting limit to %lu", lim);
360 rl.rlim_cur = lim;
361 rl.rlim_max = lim;
362 if (setrlimit(RLIMIT_AS, &rl) == -1) {
363 piglit_loge("Could not set rlimit "
364 "due to: %s (%d)",
365 strerror(errno), errno);
369 #else
370 piglit_loge("Cannot reset rlimit on this platform");
371 #endif
374 /* Merges the PASS/FAIL/SKIP for @subtest into the overall result
375 * @all.
377 * The @all should start out initialized to PIGLIT_SKIP.
379 void
380 piglit_merge_result(enum piglit_result *all, enum piglit_result subtest)
382 switch (subtest) {
383 case PIGLIT_FAIL:
384 *all = PIGLIT_FAIL;
385 break;
386 case PIGLIT_WARN:
387 if (*all == PIGLIT_SKIP || *all == PIGLIT_PASS)
388 *all = PIGLIT_WARN;
389 break;
390 case PIGLIT_PASS:
391 if (*all == PIGLIT_SKIP)
392 *all = PIGLIT_PASS;
393 break;
394 case PIGLIT_SKIP:
395 break;
399 char *piglit_load_text_file(const char *file_name, unsigned *size)
401 char *text = NULL;
403 #if defined(USE_STDIO)
404 FILE *fp;
406 # ifdef HAVE_FOPEN_S
407 errno_t err;
409 if (file_name == NULL) {
410 return NULL;
413 err = fopen_s(&fp, file_name, "r");
415 if (err || (fp == NULL)) {
416 return NULL;
418 # else
419 fp = fopen(file_name, "r");
420 if (fp == NULL) {
421 return NULL;
423 # endif
425 if (fseek(fp, 0, SEEK_END) == 0) {
426 size_t len = (size_t) ftell(fp);
427 rewind(fp);
429 text = malloc(len + 1);
430 if (text != NULL) {
431 size_t total_read = 0;
433 do {
434 size_t bytes = fread(text + total_read, 1,
435 len - total_read, fp);
437 total_read += bytes;
438 if (feof(fp)) {
439 break;
442 if (ferror(fp)) {
443 free(text);
444 text = NULL;
445 break;
447 } while (total_read < len);
449 if (text != NULL) {
450 text[total_read] = '\0';
453 if (size != NULL) {
454 *size = total_read;
459 fclose(fp);
460 return text;
461 #else
462 struct stat st;
463 int fd = open(file_name, O_RDONLY);
465 if (fd < 0) {
466 return NULL;
469 if (fstat(fd, & st) == 0) {
470 ssize_t total_read = 0;
472 if (!S_ISREG(st.st_mode) &&
473 !S_ISLNK(st.st_mode)) {
474 /* not a regular file or symlink */
475 close(fd);
476 return NULL;
479 text = malloc(st.st_size + 1);
480 if (text != NULL) {
481 do {
482 ssize_t bytes = read(fd, text + total_read,
483 st.st_size - total_read);
484 if (bytes < 0) {
485 free(text);
486 text = NULL;
487 break;
490 if (bytes == 0) {
491 break;
494 total_read += bytes;
495 } while (total_read < st.st_size);
497 text[total_read] = '\0';
498 if (size != NULL) {
499 *size = total_read;
504 close(fd);
506 return text;
507 #endif
510 const char*
511 piglit_source_dir(void)
514 const char *s = getenv("PIGLIT_SOURCE_DIR");
516 if (s == NULL) {
517 piglit_loge("env var PIGLIT_SOURCE_DIR is undefined");
518 piglit_report_result(PIGLIT_FAIL);
521 return s;
524 size_t
525 piglit_join_paths(char buf[], size_t buf_size, int n, ...)
527 char *dest = buf;
528 size_t size_written = 0;
530 int i;
531 va_list va;
533 if (buf_size == 0 || n < 1)
534 return 0;
536 va_start(va, n);
538 i = 0;
539 while (true) {
540 const char *p = va_arg(va, const char*);
542 while (*p != 0) {
543 if (size_written == buf_size - 1)
544 goto write_null;
546 *dest = *p;
547 ++dest;
548 ++p;
549 ++size_written;
552 ++i;
553 if (i == n)
554 break;
556 *dest = PIGLIT_PATH_SEP;
557 ++dest;
558 ++size_written;
561 write_null:
562 *dest = '\0';
563 ++size_written;
565 va_end(va);
566 return size_written;
569 bool
570 piglit_time_is_monotonic(void)
572 #ifdef PIGLIT_HAS_POSIX_CLOCK_MONOTONIC
573 struct timespec t;
574 int r = clock_gettime(CLOCK_MONOTONIC, &t);
576 return r == 0 || (r == -1 && errno != EINVAL);
577 #else
578 return false;
579 #endif
582 int64_t
583 piglit_time_get_nano(void)
585 #if !defined(_WIN32)
586 struct timeval tv;
588 #ifdef PIGLIT_HAS_POSIX_CLOCK_MONOTONIC
589 struct timespec t;
590 int r = clock_gettime(CLOCK_MONOTONIC, &t);
592 if (r == 0 || (r == -1 && errno != EINVAL))
593 return (t.tv_sec * INT64_C(1000000000)) + t.tv_nsec;
594 #endif
596 gettimeofday(&tv, NULL);
597 return tv.tv_usec * INT64_C(1000) + tv.tv_sec * INT64_C(1000000000);
598 #else
599 static LARGE_INTEGER frequency;
600 LARGE_INTEGER counter;
602 if (!frequency.QuadPart)
603 QueryPerformanceFrequency(&frequency);
604 QueryPerformanceCounter(&counter);
605 return counter.QuadPart * INT64_C(1000000000)/frequency.QuadPart;
606 #endif
609 int64_t
610 piglit_delay_ns(int64_t time_ns)
612 int64_t start = piglit_time_get_nano();
613 int64_t end;
615 #ifdef __linux__
616 struct timespec ts;
618 ts.tv_sec = time_ns / 1000000000LL;
619 ts.tv_nsec = time_ns - ts.tv_sec * 1000000000LL;
621 while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
623 #else
624 usleep(time_ns / 1000);
625 #endif
627 end = piglit_time_get_nano();
629 return end - start;
633 * Search for an argument with the given name in the argument list.
634 * If it is found, remove it and return true.
636 bool
637 piglit_strip_arg(int *argc, char *argv[], const char *arg)
639 int i;
640 for (i = 1; i < *argc; i++) {
641 if (strcmp(argv[i], arg) != 0)
642 continue;
644 for (i += 1; i < *argc; ++i)
645 argv[i-1] = argv[i];
647 *argc -= 1;
648 return true;
651 return false;
654 void
655 piglit_parse_subtest_args(int *argc, char *argv[],
656 const struct piglit_subtest *subtests,
657 const char ***out_selected_subtests,
658 size_t *out_num_selected_subtests)
660 int j;
661 const char **selected_subtests = NULL;
662 size_t num_selected_subtests = 0;
664 const char *usage =
665 "usage:\n"
666 " %1$s\n"
667 " Run all subtests.\n"
668 "\n"
669 " %1$s -list-subtests\n"
670 " List all subtests.\n"
671 "\n"
672 " %1$s -subtest SUBTEST [-subtest SUBTEST [...]]\n"
673 " Run only the given subtests.\n"
674 "\n"
675 " %1$s -h|--help\n"
676 " Print this help message.\n"
679 for (j = 1; j < *argc; j++) {
680 if (streq(argv[j], "-h") || streq(argv[j], "--help")) {
681 printf(usage, basename(argv[0]));
682 exit(EXIT_SUCCESS);
683 } else if (streq(argv[j], "-subtest")) {
684 int i;
686 ++j;
687 if (j >= *argc) {
688 piglit_loge("-subtest requires an argument");
689 piglit_report_result(PIGLIT_FAIL);
692 if (!piglit_find_subtest(subtests, argv[j])) {
693 piglit_loge("Test defines no subtest with "
694 "name '%s'", argv[j]);
695 piglit_report_result(PIGLIT_FAIL);
698 selected_subtests =
699 realloc(selected_subtests,
700 (num_selected_subtests + 1)
701 * sizeof(char*));
702 selected_subtests[num_selected_subtests] = argv[j];
703 ++num_selected_subtests;
705 /* Remove 2 arguments from the command line. */
706 for (i = j + 1; i < *argc; i++) {
707 argv[i - 2] = argv[i];
709 *argc -= 2;
710 j -= 2;
711 } else if (streq(argv[j], "-list-subtests")) {
712 int i;
714 if (subtests == NULL) {
715 piglit_loge("Test defines no subtests!");
716 exit(EXIT_FAILURE);
719 for (i = 0; !PIGLIT_SUBTEST_END(&subtests[i]); ++i) {
720 printf("%s: %s\n",
721 subtests[i].option,
722 subtests[i].name);
725 exit(EXIT_SUCCESS);
729 *out_selected_subtests = selected_subtests;
730 *out_num_selected_subtests = num_selected_subtests;
734 const struct piglit_subtest *
735 piglit_find_subtest(const struct piglit_subtest *subtests, const char *name)
737 unsigned i;
739 for (i = 0; !PIGLIT_SUBTEST_END(&subtests[i]); i++) {
740 if (strcmp(subtests[i].option, name) == 0)
741 return &subtests[i];
744 return NULL;
747 enum piglit_result
748 piglit_run_selected_subtests(const struct piglit_subtest *all_subtests,
749 const char **selected_subtests,
750 size_t num_selected_subtests,
751 enum piglit_result previous_result)
753 enum piglit_result result = previous_result;
755 /* print JSON list of subtests */
756 printf("PIGLIT: {\"enumerate subtests\": [");
757 if (num_selected_subtests) {
758 const char *prefix = "";
759 for (int i = 0; i < num_selected_subtests; i++) {
760 const char *const name = selected_subtests[i];
761 const struct piglit_subtest *subtest =
762 piglit_find_subtest(all_subtests, name);
764 if (subtest == NULL) {
765 printf("]}\n");
766 fflush(stdout);
767 piglit_loge("Unknown subtest \"%s\"", name);
768 piglit_report_result(PIGLIT_FAIL);
770 printf("%s\"%s\"", prefix, name);
771 prefix = ", ";
774 } else {
775 const char *prefix = "";
776 for (int i = 0; !PIGLIT_SUBTEST_END(&all_subtests[i]); i++) {
777 printf("%s\"%s\"", prefix, all_subtests[i].name);
778 prefix = ", ";
781 printf("]}\n");
782 fflush(stdout);
784 if (num_selected_subtests) {
785 for (int i = 0; i < num_selected_subtests; i++) {
786 enum piglit_result subtest_result;
787 const char *const name = selected_subtests[i];
788 const struct piglit_subtest *subtest =
789 piglit_find_subtest(all_subtests, name);
791 subtest_result = subtest->subtest_func(subtest->data);
792 piglit_report_subtest_result(subtest_result, "%s",
793 subtest->name);
795 piglit_merge_result(&result, subtest_result);
797 } else {
798 for (int i = 0; !PIGLIT_SUBTEST_END(&all_subtests[i]); i++) {
799 const enum piglit_result subtest_result =
800 all_subtests[i].subtest_func(all_subtests[i].data);
801 piglit_report_subtest_result(subtest_result, "%s",
802 all_subtests[i].name);
804 piglit_merge_result(&result, subtest_result);
808 return result;
811 void
812 piglit_register_subtests(const char *names[])
814 printf("PIGLIT: {\"enumerate subtests\": [\"%s\"", names[0]);
815 for (int i = 1; names[i]; i++) {
816 printf(", \"%s\"", names[i]);
818 printf("]}\n");
819 fflush(stdout);
822 uint64_t
823 piglit_gettid(void)
825 #ifdef __linux__
826 return syscall(SYS_gettid);
827 #else
828 return 0;
829 #endif
833 size_t
834 piglit_get_page_size(void)
836 #if defined(_WIN32)
837 SYSTEM_INFO system_info;
838 GetSystemInfo(&system_info);
839 return system_info.dwPageSize;
840 #else
841 return sysconf(_SC_PAGESIZE);
842 #endif
846 void *
847 piglit_alloc_aligned(size_t alignment, size_t size)
849 #if defined(_WIN32)
850 return _aligned_malloc(size, alignment);
851 #else
852 void *p;
853 if (posix_memalign(&p, alignment, size) != 0) {
854 return NULL;
856 return p;
857 #endif
861 void
862 piglit_free_aligned(void *p)
864 #if defined(_WIN32)
865 _aligned_free(p);
866 #else
867 free(p);
868 #endif
873 * \brief Reads an environment variable and interprets its value as a boolean.
875 * Recognizes 0/false/no and 1/true/yes. Other values result in the
876 * \a default_value.
878 bool
879 piglit_env_var_as_boolean(const char *var_name, bool default_value)
881 const char *str = getenv(var_name);
882 if (str == NULL)
883 return default_value;
885 if (strcmp(str, "1") == 0 ||
886 strcasecmp(str, "true") == 0 ||
887 strcasecmp(str, "yes") == 0) {
888 return true;
889 } else if (strcmp(str, "0") == 0 ||
890 strcasecmp(str, "false") == 0 ||
891 strcasecmp(str, "no") == 0) {
892 return false;
893 } else {
894 return default_value;