authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-19 12:07:56-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-19 12:07:56-05:00
logdb74832e40f98960e5dc3e46c8196c59033ee0f9
tree95d7e039968d665d0e0001c45c9c9c1f3e2a622d
parentc9fb5240d6305bcef7db5e12b7676ba3d741c11e
signature Commit is signed but in an unrecognized format.

valgrind client requests for undefined values

with this change, when you assign undefined, zig emits a few assembly instructions to tell valgrind that the memory is undefined it's on by default for debug builds, and disabled otherwise. only support for linux, darwin, solaris, mingw on x86_64 is currently implemented. --disable-valgrind turns it off even in debug mode. --enable-valgrind turns it on even in release modes. It's always disabled for compiler_rt.a and builtin.a. Adds `@import("builtin").valgrind_support` which lets code know at comptime whether valgrind client requests are enabled. See #1989

6 files changed, 130 insertions(+), 9 deletions(-)

src/all_types.hpp+18-6
...@@ -1345,15 +1345,11 @@ struct ZigFn {...@@ -1345,15 +1345,11 @@ struct ZigFn {
1345 // in the case of async functions this is the implicit return type according to the1345 // in the case of async functions this is the implicit return type according to the
1346 // zig source code, not according to zig ir1346 // zig source code, not according to zig ir
1347 ZigType *src_implicit_return_type;1347 ZigType *src_implicit_return_type;
1348 bool is_test;
1349 FnInline fn_inline;
1350 FnAnalState anal_state;
1351 IrExecutable ir_executable;1348 IrExecutable ir_executable;
1352 IrExecutable analyzed_executable;1349 IrExecutable analyzed_executable;
1353 size_t prealloc_bbc;1350 size_t prealloc_bbc;
1354 AstNode **param_source_nodes;1351 AstNode **param_source_nodes;
1355 Buf **param_names;1352 Buf **param_names;
1356 uint32_t align_bytes;
13571353
1358 AstNode *fn_no_inline_set_node;1354 AstNode *fn_no_inline_set_node;
1359 AstNode *fn_static_eval_set_node;1355 AstNode *fn_static_eval_set_node;
...@@ -1363,13 +1359,22 @@ struct ZigFn {...@@ -1363,13 +1359,22 @@ struct ZigFn {
13631359
1364 Buf *section_name;1360 Buf *section_name;
1365 AstNode *set_alignstack_node;1361 AstNode *set_alignstack_node;
1366 uint32_t alignstack_value;
13671362
1368 AstNode *set_cold_node;1363 AstNode *set_cold_node;
1369 bool is_cold;
13701364
1371 ZigList<FnExport> export_list;1365 ZigList<FnExport> export_list;
1366
1367 LLVMValueRef valgrind_client_request_array;
1368
1369 FnInline fn_inline;
1370 FnAnalState anal_state;
1371
1372 uint32_t align_bytes;
1373 uint32_t alignstack_value;
1374
1372 bool calls_or_awaits_errorable_fn;1375 bool calls_or_awaits_errorable_fn;
1376 bool is_cold;
1377 bool is_test;
1373};1378};
13741379
1375uint32_t fn_table_entry_hash(ZigFn*);1380uint32_t fn_table_entry_hash(ZigFn*);
...@@ -1612,6 +1617,12 @@ struct LinkLib {...@@ -1612,6 +1617,12 @@ struct LinkLib {
1612 bool provided_explicitly;1617 bool provided_explicitly;
1613};1618};
16141619
1620enum ValgrindSupport {
1621 ValgrindSupportAuto,
1622 ValgrindSupportDisabled,
1623 ValgrindSupportEnabled,
1624};
1625
1615// When adding fields, check if they should be added to the hash computation in build_with_cache1626// When adding fields, check if they should be added to the hash computation in build_with_cache
1616struct CodeGen {1627struct CodeGen {
1617 //////////////////////////// Runtime State1628 //////////////////////////// Runtime State
...@@ -1813,6 +1824,7 @@ struct CodeGen {...@@ -1813,6 +1824,7 @@ struct CodeGen {
1813 OutType out_type;1824 OutType out_type;
1814 ZigTarget zig_target;1825 ZigTarget zig_target;
1815 TargetSubsystem subsystem;1826 TargetSubsystem subsystem;
1827 ValgrindSupport valgrind_support;
1816 bool is_static;1828 bool is_static;
1817 bool strip_debug_symbols;1829 bool strip_debug_symbols;
1818 bool is_test_build;1830 bool is_test_build;
src/codegen.cpp+81
...@@ -3341,6 +3341,77 @@ static bool value_is_all_undef(ConstExprValue *const_val) {...@@ -3341,6 +3341,77 @@ static bool value_is_all_undef(ConstExprValue *const_val) {
3341 zig_unreachable();3341 zig_unreachable();
3342}3342}
33433343
3344static LLVMValueRef gen_valgrind_client_request(CodeGen *g, LLVMValueRef default_value, LLVMValueRef request,
3345 LLVMValueRef a1, LLVMValueRef a2, LLVMValueRef a3, LLVMValueRef a4, LLVMValueRef a5)
3346{
3347 if (!target_has_valgrind_support(&g->zig_target)) {
3348 return default_value;
3349 }
3350 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
3351 bool asm_has_side_effects = true;
3352 bool asm_is_alignstack = false;
3353 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3354 if (g->zig_target.os == OsLinux || target_is_darwin(&g->zig_target) || g->zig_target.os == OsSolaris ||
3355 (g->zig_target.os == OsWindows && g->zig_target.env_type != ZigLLVM_MSVC))
3356 {
3357 if (g->cur_fn->valgrind_client_request_array == nullptr) {
3358 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
3359 LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(g->cur_fn->llvm_value);
3360 LLVMValueRef first_inst = LLVMGetFirstInstruction(entry_block);
3361 LLVMPositionBuilderBefore(g->builder, first_inst);
3362 LLVMTypeRef array_type_ref = LLVMArrayType(usize_type_ref, 6);
3363 g->cur_fn->valgrind_client_request_array = LLVMBuildAlloca(g->builder, array_type_ref, "");
3364 LLVMPositionBuilderAtEnd(g->builder, prev_block);
3365 }
3366 LLVMValueRef array_ptr = g->cur_fn->valgrind_client_request_array;
3367 LLVMValueRef array_elements[] = {request, a1, a2, a3, a4, a5};
3368 LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false);
3369 for (unsigned i = 0; i < 6; i += 1) {
3370 LLVMValueRef indexes[] = {
3371 zero,
3372 LLVMConstInt(usize_type_ref, i, false),
3373 };
3374 LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indexes, 2, "");
3375 LLVMBuildStore(g->builder, array_elements[i], elem_ptr);
3376 }
3377
3378 Buf *asm_template = buf_create_from_str(
3379 "rolq $$3, %rdi ; rolq $$13, %rdi\n"
3380 "rolq $$61, %rdi ; rolq $$51, %rdi\n"
3381 "xchgq %rbx,%rbx\n"
3382 );
3383 Buf *asm_constraints = buf_create_from_str(
3384 "={rdx},{rax},0,~{cc},~{memory}"
3385 );
3386 unsigned input_and_output_count = 2;
3387 LLVMValueRef array_ptr_as_usize = LLVMBuildPtrToInt(g->builder, array_ptr, usize_type_ref, "");
3388 LLVMValueRef param_values[] = { array_ptr_as_usize, default_value };
3389 LLVMTypeRef param_types[] = {usize_type_ref, usize_type_ref};
3390 LLVMTypeRef function_type = LLVMFunctionType(usize_type_ref, param_types,
3391 input_and_output_count, false);
3392 LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(asm_template), buf_len(asm_template),
3393 buf_ptr(asm_constraints), buf_len(asm_constraints), asm_has_side_effects, asm_is_alignstack,
3394 LLVMInlineAsmDialectATT);
3395 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
3396 }
3397 }
3398 zig_unreachable();
3399}
3400
3401static bool want_valgrind_support(CodeGen *g) {
3402 if (!target_has_valgrind_support(&g->zig_target))
3403 return false;
3404 switch (g->valgrind_support) {
3405 case ValgrindSupportDisabled:
3406 return false;
3407 case ValgrindSupportEnabled:
3408 return true;
3409 case ValgrindSupportAuto:
3410 return g->build_mode == BuildModeDebug;
3411 }
3412 zig_unreachable();
3413}
3414
3344static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {3415static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
3345 assert(type_has_bits(value_type));3416 assert(type_has_bits(value_type));
3346 uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);3417 uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
...@@ -3353,6 +3424,14 @@ static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_...@@ -3353,6 +3424,14 @@ static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_
3353 ZigType *usize = g->builtin_types.entry_usize;3424 ZigType *usize = g->builtin_types.entry_usize;
3354 LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);3425 LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
3355 ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);3426 ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
3427 // then tell valgrind that the memory is undefined even though we just memset it
3428 if (want_valgrind_support(g)) {
3429 static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
3430 LLVMValueRef zero = LLVMConstInt(usize->type_ref, 0, false);
3431 LLVMValueRef req = LLVMConstInt(usize->type_ref, VG_USERREQ__MAKE_MEM_UNDEFINED, false);
3432 LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->type_ref, "");
3433 gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero);
3434 }
3356}3435}
33573436
3358static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {3437static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
...@@ -7525,6 +7604,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -7525,6 +7604,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
7525 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));7604 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
7526 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));7605 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
7527 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));7606 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
7607 buf_appendf(contents, "pub const valgrind_support = %s;\n", bool_to_str(want_valgrind_support(g)));
75287608
7529 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");7609 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
75307610
...@@ -8489,6 +8569,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -8489,6 +8569,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
8489 cache_bool(ch, g->linker_rdynamic);8569 cache_bool(ch, g->linker_rdynamic);
8490 cache_bool(ch, g->each_lib_rpath);8570 cache_bool(ch, g->each_lib_rpath);
8491 cache_bool(ch, g->disable_pic);8571 cache_bool(ch, g->disable_pic);
8572 cache_bool(ch, g->valgrind_support);
8492 cache_buf_opt(ch, g->mmacosx_version_min);8573 cache_buf_opt(ch, g->mmacosx_version_min);
8493 cache_buf_opt(ch, g->mios_version_min);8574 cache_buf_opt(ch, g->mios_version_min);
8494 cache_usize(ch, g->version_major);8575 cache_usize(ch, g->version_major);
src/link.cpp+1
...@@ -55,6 +55,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)...@@ -55,6 +55,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
55 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);55 codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
56 codegen_set_is_static(child_gen, true);56 codegen_set_is_static(child_gen, true);
57 child_gen->disable_pic = parent_gen->disable_pic;57 child_gen->disable_pic = parent_gen->disable_pic;
58 child_gen->valgrind_support = ValgrindSupportDisabled;
5859
59 codegen_set_out_name(child_gen, buf_create_from_str(aname));60 codegen_set_out_name(child_gen, buf_create_from_str(aname));
6061
src/main.cpp+11
...@@ -49,6 +49,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -49,6 +49,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
49 " --cache [auto|off|on] build in global cache, print out paths to stdout\n"49 " --cache [auto|off|on] build in global cache, print out paths to stdout\n"
50 " --color [auto|off|on] enable or disable colored error messages\n"50 " --color [auto|off|on] enable or disable colored error messages\n"
51 " --disable-pic disable Position Independent Code for libraries\n"51 " --disable-pic disable Position Independent Code for libraries\n"
52 " --disable-valgrind omit valgrind client requests in debug builds\n"
53 " --enable-valgrind include valgrind client requests release builds\n"
52 " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"54 " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
53 " -ftime-report print timing diagnostics\n"55 " -ftime-report print timing diagnostics\n"
54 " --libc-include-dir [path] directory where libc stdlib.h resides\n"56 " --libc-include-dir [path] directory where libc stdlib.h resides\n"
...@@ -396,6 +398,7 @@ int main(int argc, char **argv) {...@@ -396,6 +398,7 @@ int main(int argc, char **argv) {
396 TargetSubsystem subsystem = TargetSubsystemAuto;398 TargetSubsystem subsystem = TargetSubsystemAuto;
397 bool is_single_threaded = false;399 bool is_single_threaded = false;
398 Buf *override_std_dir = nullptr;400 Buf *override_std_dir = nullptr;
401 ValgrindSupport valgrind_support = ValgrindSupportAuto;
399402
400 if (argc >= 2 && strcmp(argv[1], "build") == 0) {403 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
401 Buf zig_exe_path_buf = BUF_INIT;404 Buf zig_exe_path_buf = BUF_INIT;
...@@ -433,6 +436,7 @@ int main(int argc, char **argv) {...@@ -433,6 +436,7 @@ int main(int argc, char **argv) {
433436
434 CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),437 CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
435 override_std_dir);438 override_std_dir);
439 g->valgrind_support = valgrind_support;
436 g->enable_time_report = timing_info;440 g->enable_time_report = timing_info;
437 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);441 buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
438 codegen_set_out_name(g, buf_create_from_str("build"));442 codegen_set_out_name(g, buf_create_from_str("build"));
...@@ -520,6 +524,7 @@ int main(int argc, char **argv) {...@@ -520,6 +524,7 @@ int main(int argc, char **argv) {
520 os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);524 os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
521 CodeGen *g = codegen_create(fmt_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),525 CodeGen *g = codegen_create(fmt_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
522 nullptr);526 nullptr);
527 g->valgrind_support = valgrind_support;
523 g->is_single_threaded = true;528 g->is_single_threaded = true;
524 codegen_set_out_name(g, buf_create_from_str("fmt"));529 codegen_set_out_name(g, buf_create_from_str("fmt"));
525 g->enable_cache = true;530 g->enable_cache = true;
...@@ -577,6 +582,10 @@ int main(int argc, char **argv) {...@@ -577,6 +582,10 @@ int main(int argc, char **argv) {
577 timing_info = true;582 timing_info = true;
578 } else if (strcmp(arg, "--disable-pic") == 0) {583 } else if (strcmp(arg, "--disable-pic") == 0) {
579 disable_pic = true;584 disable_pic = true;
585 } else if (strcmp(arg, "--enable-valgrind") == 0) {
586 valgrind_support = ValgrindSupportEnabled;
587 } else if (strcmp(arg, "--disable-valgrind") == 0) {
588 valgrind_support = ValgrindSupportDisabled;
580 } else if (strcmp(arg, "--system-linker-hack") == 0) {589 } else if (strcmp(arg, "--system-linker-hack") == 0) {
581 system_linker_hack = true;590 system_linker_hack = true;
582 } else if (strcmp(arg, "--single-threaded") == 0) {591 } else if (strcmp(arg, "--single-threaded") == 0) {
...@@ -849,6 +858,7 @@ int main(int argc, char **argv) {...@@ -849,6 +858,7 @@ int main(int argc, char **argv) {
849 switch (cmd) {858 switch (cmd) {
850 case CmdBuiltin: {859 case CmdBuiltin: {
851 CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir);860 CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir);
861 g->valgrind_support = valgrind_support;
852 g->is_single_threaded = is_single_threaded;862 g->is_single_threaded = is_single_threaded;
853 Buf *builtin_source = codegen_generate_builtin_source(g);863 Buf *builtin_source = codegen_generate_builtin_source(g);
854 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {864 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
...@@ -909,6 +919,7 @@ int main(int argc, char **argv) {...@@ -909,6 +919,7 @@ int main(int argc, char **argv) {
909 }919 }
910 CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(),920 CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(),
911 override_std_dir);921 override_std_dir);
922 g->valgrind_support = valgrind_support;
912 g->subsystem = subsystem;923 g->subsystem = subsystem;
913924
914 if (disable_pic) {925 if (disable_pic) {
src/target.cpp+17-3
...@@ -544,7 +544,7 @@ void get_target_triple(Buf *triple, const ZigTarget *target) {...@@ -544,7 +544,7 @@ void get_target_triple(Buf *triple, const ZigTarget *target) {
544 }544 }
545}545}
546546
547static bool is_os_darwin(ZigTarget *target) {547bool target_is_darwin(const ZigTarget *target) {
548 switch (target->os) {548 switch (target->os) {
549 case OsMacOSX:549 case OsMacOSX:
550 case OsIOS:550 case OsIOS:
...@@ -566,7 +566,7 @@ void resolve_target_object_format(ZigTarget *target) {...@@ -566,7 +566,7 @@ void resolve_target_object_format(ZigTarget *target) {
566 case ZigLLVM_thumb:566 case ZigLLVM_thumb:
567 case ZigLLVM_x86:567 case ZigLLVM_x86:
568 case ZigLLVM_x86_64:568 case ZigLLVM_x86_64:
569 if (is_os_darwin(target)) {569 if (target_is_darwin(target)) {
570 target->oformat = ZigLLVM_MachO;570 target->oformat = ZigLLVM_MachO;
571 } else if (target->os == OsWindows) {571 } else if (target->os == OsWindows) {
572 target->oformat = ZigLLVM_COFF;572 target->oformat = ZigLLVM_COFF;
...@@ -626,7 +626,7 @@ void resolve_target_object_format(ZigTarget *target) {...@@ -626,7 +626,7 @@ void resolve_target_object_format(ZigTarget *target) {
626626
627 case ZigLLVM_ppc:627 case ZigLLVM_ppc:
628 case ZigLLVM_ppc64:628 case ZigLLVM_ppc64:
629 if (is_os_darwin(target)) {629 if (target_is_darwin(target)) {
630 target->oformat = ZigLLVM_MachO;630 target->oformat = ZigLLVM_MachO;
631 } else {631 } else {
632 target->oformat= ZigLLVM_ELF;632 target->oformat= ZigLLVM_ELF;
...@@ -1084,3 +1084,17 @@ bool target_is_arm(const ZigTarget *target) {...@@ -1084,3 +1084,17 @@ bool target_is_arm(const ZigTarget *target) {
1084 }1084 }
1085 zig_unreachable();1085 zig_unreachable();
1086}1086}
1087
1088// Valgrind supports more, but Zig does not support them yet.
1089bool target_has_valgrind_support(const ZigTarget *target) {
1090 switch (target->arch.arch) {
1091 case ZigLLVM_UnknownArch:
1092 zig_unreachable();
1093 case ZigLLVM_x86_64:
1094 return (target->os == OsLinux || target_is_darwin(target) || target->os == OsSolaris ||
1095 (target->os == OsWindows && target->env_type != ZigLLVM_MSVC));
1096 default:
1097 return false;
1098 }
1099 zig_unreachable();
1100}
src/target.hpp+2
...@@ -136,5 +136,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type);...@@ -136,5 +136,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type);
136136
137bool target_is_arm(const ZigTarget *target);137bool target_is_arm(const ZigTarget *target);
138bool target_allows_addr_zero(const ZigTarget *target);138bool target_allows_addr_zero(const ZigTarget *target);
139bool target_has_valgrind_support(const ZigTarget *target);
140bool target_is_darwin(const ZigTarget *target);
139141
140#endif142#endif