memcheck.odin 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //+build amd64
  2. package sys_valgrind
  3. import "core:intrinsics"
  4. Mem_Check_Client_Request :: enum uintptr {
  5. Make_Mem_No_Access = 'M'<<24 | 'C'<<16,
  6. Make_Mem_Undefined,
  7. Make_Mem_Defined,
  8. Discard,
  9. Check_Mem_Is_Addressable,
  10. Check_Mem_Is_Defined,
  11. Do_Leak_Check,
  12. Count_Leaks,
  13. Get_Vbits,
  14. Set_Vbits,
  15. Create_Block,
  16. Make_Mem_Defined_If_Addressable,
  17. Count_Leak_Blocks,
  18. Enable_Addr_Error_Reporting_In_Range,
  19. Disable_Addr_Error_Reporting_In_Range,
  20. }
  21. @(require_results)
  22. mem_check_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
  23. return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
  24. }
  25. mem_check_client_request_stmt :: #force_inline proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
  26. _ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
  27. }
  28. // Mark memory at `raw_data(qzz)` as unaddressable for `len(qzz)` bytes.
  29. // Returns true when run on Valgrind and false otherwise.
  30. make_mem_no_access :: proc "c" (qzz: []byte) -> bool {
  31. return 0 != mem_check_client_request_expr(0, .Make_Mem_No_Access, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  32. }
  33. // Mark memory at `raw_data(qzz)` as addressable but undefined for `len(qzz)` bytes.
  34. // Returns true when run on Valgrind and false otherwise.
  35. make_mem_undefined :: proc "c" (qzz: []byte) -> bool {
  36. return 0 != mem_check_client_request_expr(0, .Make_Mem_Undefined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  37. }
  38. // Mark memory at `raw_data(qzz)` as addressable for `len(qzz)` bytes.
  39. // Returns true when run on Valgrind and false otherwise.
  40. make_mem_defined :: proc "c" (qzz: []byte) -> bool {
  41. return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  42. }
  43. // Check that memory at `raw_data(qzz)` is addressable for `len(qzz)` bytes.
  44. // If suitable addressibility is not established, Valgrind prints an error
  45. // message and returns the address of the first offending byte.
  46. // Otherwise it returns zero.
  47. check_mem_is_addressable :: proc "c" (qzz: []byte) -> uintptr {
  48. return mem_check_client_request_expr(0, .Check_Mem_Is_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  49. }
  50. // Check that memory at `raw_data(qzz)` is addressable and defined for `len(qzz)` bytes.
  51. // If suitable addressibility and definedness are not established,
  52. // Valgrind prints an error message and returns the address of the first
  53. // offending byte. Otherwise it returns zero.
  54. check_mem_is_defined :: proc "c" (qzz: []byte) -> uintptr {
  55. return mem_check_client_request_expr(0, .Check_Mem_Is_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  56. }
  57. // Similar to `make_mem_defined(qzz)` except that addressability is not altered:
  58. // bytes which are addressable are marked as defined, but those which
  59. // are not addressable are left unchanged.
  60. // Returns true when run on Valgrind and false otherwise.
  61. make_mem_defined_if_addressable :: proc "c" (qzz: []byte) -> bool {
  62. return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined_If_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  63. }
  64. // Create a block-description handle.
  65. // The description is an ascii string which is included in any messages
  66. // pertaining to addresses within the specified memory range.
  67. // Has no other effect on the properties of the memory range.
  68. create_block :: proc "c" (qzz: []u8, desc: cstring) -> bool {
  69. return 0 != mem_check_client_request_expr(0, .Create_Block, uintptr(raw_data(qzz)), uintptr(len(qzz)), uintptr(rawptr(desc)), 0, 0)
  70. }
  71. // Discard a block-description-handle. Returns true for an invalid handle, false for a valid handle.
  72. discard :: proc "c" (blk_index: uintptr) -> bool {
  73. return 0 != mem_check_client_request_expr(0, .Discard, 0, blk_index, 0, 0, 0)
  74. }
  75. // Do a full memory leak check (like `--leak-check=full`) mid-execution.
  76. leak_check :: proc "c" () {
  77. mem_check_client_request_stmt(.Do_Leak_Check, 0, 0, 0, 0, 0)
  78. }
  79. // Same as `leak_check()` but only showing the entries for which there was an increase
  80. // in leaked bytes or leaked nr of blocks since the previous leak search.
  81. added_leak_check :: proc "c" () {
  82. mem_check_client_request_stmt(.Do_Leak_Check, 0, 1, 0, 0, 0)
  83. }
  84. // Same as `added_leak_check()` but showing entries with increased or decreased
  85. // leaked bytes/blocks since previous leak search.
  86. changed_leak_check :: proc "c" () {
  87. mem_check_client_request_stmt(.Do_Leak_Check, 0, 2, 0, 0, 0)
  88. }
  89. // Do a summary memory leak check (like `--leak-check=summary`) mid-execution.
  90. quick_leak_check :: proc "c" () {
  91. mem_check_client_request_stmt(.Do_Leak_Check, 1, 0, 0, 0, 0)
  92. }
  93. Count_Result :: struct {
  94. leaked: uint,
  95. dubious: uint,
  96. reachable: uint,
  97. suppressed: uint,
  98. }
  99. count_leaks :: proc "c" () -> (res: Count_Result) {
  100. mem_check_client_request_stmt(
  101. .Count_Leaks,
  102. uintptr(&res.leaked),
  103. uintptr(&res.dubious),
  104. uintptr(&res.reachable),
  105. uintptr(&res.suppressed),
  106. 0,
  107. )
  108. return
  109. }
  110. count_leak_blocks :: proc "c" () -> (res: Count_Result) {
  111. mem_check_client_request_stmt(
  112. .Count_Leak_Blocks,
  113. uintptr(&res.leaked),
  114. uintptr(&res.dubious),
  115. uintptr(&res.reachable),
  116. uintptr(&res.suppressed),
  117. 0,
  118. )
  119. return
  120. }
  121. // Get the validity data for addresses zza and copy it
  122. // into the provided zzvbits array. Return values:
  123. // 0 - if not running on valgrind
  124. // 1 - success
  125. // 2 - [previously indicated unaligned arrays; these are now allowed]
  126. // 3 - if any parts of zzsrc/zzvbits are not addressable.
  127. // The metadata is not copied in cases 0, 2 or 3 so it should be
  128. // impossible to segfault your system by using this call.
  129. get_vbits :: proc(zza, zzvbits: []byte) -> u8 {
  130. // assert requires a `context` thus these procedures cannot `proc "c"`
  131. assert(len(zzvbits) >= len(zza)/8)
  132. return u8(mem_check_client_request_expr(0, .Get_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
  133. }
  134. // Set the validity data for addresses zza, copying it
  135. // from the provided zzvbits array. Return values:
  136. // 0 - if not running on valgrind
  137. // 1 - success
  138. // 2 - [previously indicated unaligned arrays; these are now allowed]
  139. // 3 - if any parts of zza/zzvbits are not addressable.
  140. // The metadata is not copied in cases 0, 2 or 3 so it should be
  141. // impossible to segfault your system by using this call.
  142. set_vbits :: proc(zzvbits, zza: []byte) -> u8 {
  143. // assert requires a `context` thus these procedures cannot `proc "c"`
  144. assert(len(zzvbits) >= len(zza)/8)
  145. return u8(mem_check_client_request_expr(0, .Set_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
  146. }
  147. // (Re-)enable reporting of addressing errors in the specified address range.
  148. enable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
  149. return mem_check_client_request_expr(0, .Enable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  150. }
  151. // Disable reporting of addressing errors in the specified address range.
  152. disable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
  153. return mem_check_client_request_expr(0, .Disable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
  154. }