// RUN: %empty-directory(%t) // RUN: %clang %target-cc-options -g -O0 -isysroot %sdk -I %swift_src_root/stdlib/public/Darwin/os -framework Foundation %swift_src_root/stdlib/public/Darwin/os/format.m %swift_src_root/stdlib/public/Darwin/os/os_trace_blob.c %s -o %t/os_log_format // RUN: %target-run %t/os_log_format | %FileCheck %s // REQUIRES: objc_interop // REQUIRES: executable_test #import #import #import "format.h" // CHECK-NOT: FAIL // CHECK: PASS static bool compare_buffers(char *fail_prefix, char *bufa, char *bufb, size_t size) { if (!memcmp(bufa, bufb, size)) { return true; } os_log_fmt_hdr_t hdra = (os_log_fmt_hdr_t)bufa; os_log_fmt_hdr_t hdrb = (os_log_fmt_hdr_t)bufb; if (hdra->hdr_flags != hdrb->hdr_flags) { printf("FAIL: %s: header flags mismatch (0x%x != 0x%x)\n", fail_prefix, hdra->hdr_flags, hdrb->hdr_flags); return false; } if (hdra->hdr_cmd_cnt != hdrb->hdr_cmd_cnt) { printf("FAIL: %s: command count mismatch (0x%x != 0x%x)\n", fail_prefix, hdra->hdr_cmd_cnt, hdrb->hdr_cmd_cnt); return false; } os_log_fmt_cmd_t cmda = (os_log_fmt_cmd_t)((uint8_t *)hdra + sizeof(os_log_fmt_hdr_s)); os_log_fmt_cmd_t cmdb = (os_log_fmt_cmd_t)((uint8_t *)hdrb + sizeof(os_log_fmt_hdr_s)); for (size_t idx = 0; idx < hdra->hdr_cmd_cnt; idx++) { if (cmda->cmd_flags != cmdb->cmd_flags) { printf("FAIL: %s: command %zu flags mismatch (0x%x != 0x%x)\n", fail_prefix, idx, cmda->cmd_flags, cmdb->cmd_flags); return false; } if (cmda->cmd_type != cmdb->cmd_type) { printf("FAIL: %s: command %zu type mismatch (0x%x != 0x%x)\n", fail_prefix, idx, cmda->cmd_type, cmdb->cmd_type); return false; } if (cmda->cmd_size != cmdb->cmd_size) { printf("FAIL: %s: command %zu size mismatch (0x%x != 0x%x)\n", fail_prefix, idx, cmda->cmd_size, cmdb->cmd_size); return false; } if (memcmp(cmda->cmd_data, cmdb->cmd_data, cmda->cmd_size)) { printf("FAIL: %s: command %zu data mismatch\n", fail_prefix, idx); printf("COMPILER: "); for (size_t i=0; icmd_size; i++) { printf("%02x ", cmda->cmd_data[i]); } printf("\nOVERLAY: "); for (size_t i=0; icmd_size; i++) { printf("%02x ", cmdb->cmd_data[i]); } printf("\n"); return false; } cmda = (os_log_fmt_cmd_t)((uint8_t *)cmda + sizeof(os_log_fmt_cmd_s) + cmda->cmd_size); cmdb = (os_log_fmt_cmd_t)((uint8_t *)cmdb + sizeof(os_log_fmt_cmd_s) + cmdb->cmd_size); } return true; } static bool _t_log_encode(char buf[OS_LOG_FMT_BUF_SIZE], int saved_errno, os_trace_blob_t blob, const char *format, ...) { va_list va; bool rv; va_start(va, format); rv = _os_log_encode(buf, format, va, saved_errno, blob); va_end(va); return rv; } #define compiler_format(buf, fmt, ...) ({ \ __builtin_os_log_format(buf, fmt, ##__VA_ARGS__); \ (uint32_t)__builtin_os_log_format_buffer_size(fmt, ##__VA_ARGS__); \ }) #define overlay_format(buf, fmt, ...) ({ \ os_trace_blob_s ob = { \ .ob_s = os_trace_buf, \ .ob_size = OS_LOG_FMT_BUF_SIZE, \ .ob_maxsize = OS_LOG_FMT_BUF_SIZE, \ .ob_binary = true \ }; \ _t_log_encode(os_trace_buf, 0, &ob, fmt, ##__VA_ARGS__); \ (uint32_t)ob.ob_len; \ }) int main(int argc, char **argv) { static char compiler_buf[8192]; static char os_trace_buf[OS_LOG_FMT_BUF_SIZE]; uint32_t compiler_size, our_size; int i; #define ACCEPT(_fmt, ...) ({ \ compiler_size = compiler_format(compiler_buf, _fmt, ##__VA_ARGS__); \ our_size = overlay_format(os_trace_buf, _fmt, ##__VA_ARGS__); \ if (!compare_buffers("during: \"" _fmt "\"", compiler_buf, os_trace_buf, \ our_size)) { \ exit(1); \ } \ }) ACCEPT("doesn't even have an argument"); ACCEPT("simple char %hhd", (char)10); ACCEPT("simple short %hd", (short)10); ACCEPT("simple integer %d", 10); ACCEPT("simple long long %lld", (long long)10); ACCEPT("simple pointer %p", "sad"); ACCEPT("simple float %f", (float)1.5); ACCEPT("simple double %f", 1.5); #ifdef __LP64__ // Disabled because the upstream clang output for long double changed // and causes CI fallout // ACCEPT("simple long double %Lf", (long double)1.5); #endif ACCEPT("integer with a static width %666d", 10); ACCEPT("integer with a static precision %.42d", 10); ACCEPT("integer with a static width & precision %666.42d", 10); ACCEPT("integer with dynamic width %*d", 666, 10); ACCEPT("integer with dynamic precision %.*d", 42, 10); ACCEPT("integer with dynamic width & precision %*.*d", 666, 42, 10); // All the %s tests below are disabled for the overlay because // the overlay assumes %s really means %@. // ACCEPT("simple string %s", "sad"); // ACCEPT("string with a static width %666s", "sad"); // ACCEPT("string with a static precision %.42s", "sad"); // ACCEPT("string with a static width & precision %666.42s", "sad"); // ACCEPT("string with dynamic width %*s", 666, "sad"); // ACCEPT("string with dynamic precision %.*s", 42, "sad"); // ACCEPT("string with dynamic width & precision %*.*s", 666, 42, "sad"); ACCEPT("data with a static precision %.42P", "sad"); ACCEPT("data with a static width & precision %666.42P", "sad"); ACCEPT("data with dynamic precision %.*P", 42, "sad"); ACCEPT("data with dynamic width & precision %*.*P", 666, 42, "sad"); ACCEPT("simple object %@", @"sad"); ACCEPT("object with a static width %666@", @"sad"); ACCEPT("object with dynamic width %*@", 666, @"sad"); // privacy and annotations ACCEPT("simple integer %{public}d", 10); ACCEPT("simple integer %{private}d", 10); ACCEPT("simple integer %{public, blah}d", 10); ACCEPT("simple integer %{public, builtin:blah::bluh}d", 10); ACCEPT("integer with a static width %{private}666d", 10); ACCEPT("integer with a static precision %{private}.42d", 10); ACCEPT("integer with a static width & precision %{private}666.42d", 10); ACCEPT("integer with dynamic width %{private}*d", 666, 10); ACCEPT("integer with dynamic precision %{private}.*d", 42, 10); ACCEPT("integer with dynamic width & precision %{private}*.*d", 666, 42, 10); // ACCEPT("simple string %{private}s", "sad"); // ACCEPT("string with a static width %{private}666s", "sad"); // ACCEPT("string with a static precision %{private}.42s", "sad"); // ACCEPT("string with a static width & precision %{private}666.42s", "sad"); // ACCEPT("string with dynamic width %{private}*s", 666, "sad"); // ACCEPT("string with dynamic precision %{private}.*s", 42, "sad"); // ACCEPT("string with dynamic width & precision %{private}*.*s", 666, 42, "sad"); ACCEPT("data with a static precision %{private}.42P", "sad"); ACCEPT("data with a static width & precision %{private}666.42P", "sad"); ACCEPT("data with dynamic precision %{private}.*P", 42, "sad"); ACCEPT("data with dynamic width & precision %{private}*.*P", 666, 42, "sad"); ACCEPT("simple object %{private}@", @"sad"); ACCEPT("object with a static width %{private}666@", @"sad"); ACCEPT("object with dynamic width %{private}*@", 666, @"sad"); printf("PASS\n"); }