Browse Source

Merge pull request #5142 from laytan/abi-and-asan-fixes

tests/internal with asan (requiring abi and codegen fixes), and macos -sanitize:address
gingerBill 4 months ago
parent
commit
8e17ccfd98
4 changed files with 91 additions and 80 deletions
  1. 21 49
      .github/workflows/ci.yml
  2. 1 0
      base/runtime/internal.odin
  3. 14 28
      src/llvm_abi.cpp
  4. 55 3
      src/llvm_backend_general.cpp

+ 21 - 49
.github/workflows/ci.yml

@@ -75,9 +75,9 @@ jobs:
       fail-fast: false
       fail-fast: false
       matrix:
       matrix:
         # MacOS 13 runs on Intel, 14 runs on ARM
         # MacOS 13 runs on Intel, 14 runs on ARM
-        os: [macos-13, macos-14]
+        os: [macos-13, macos-14, ubuntu-latest]
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
-    name: ${{ matrix.os == 'macos-14' && 'MacOS ARM' || (matrix.os == 'macos-13' && 'MacOS Intel') }} Build, Check, and Test
+    name: ${{ matrix.os == 'macos-14' && 'MacOS ARM' || (matrix.os == 'macos-13' && 'MacOS Intel') || (matrix.os == 'ubuntu-latest' && 'Ubuntu') }} Build, Check, and Test
     timeout-minutes: 15
     timeout-minutes: 15
     steps:
     steps:
 
 
@@ -88,59 +88,17 @@ jobs:
         run: |
         run: |
           brew update
           brew update
           brew install llvm@20 [email protected] lld
           brew install llvm@20 [email protected] lld
+          echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH
 
 
       - name: Download LLVM (MacOS ARM)
       - name: Download LLVM (MacOS ARM)
         if: matrix.os == 'macos-14'
         if: matrix.os == 'macos-14'
         run: |
         run: |
           brew update
           brew update
           brew install llvm@20 wasmtime [email protected] lld
           brew install llvm@20 wasmtime [email protected] lld
+          echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH
 
 
-      - name: Build Odin
-        run: ./build_odin.sh release
-      - name: Odin version
-        run: ./odin version
-      - name: Odin report
-        run: ./odin report
-      - name: Compile needed Vendor
-        run: |
-          make -C vendor/stb/src
-          make -C vendor/cgltf/src
-          make -C vendor/miniaudio/src
-      - name: Odin check
-        run: ./odin check examples/demo -vet
-      - name: Odin run
-        run: ./odin run examples/demo
-      - name: Odin run -debug
-        run: ./odin run examples/demo -debug
-      - name: Odin check examples/all
-        run: ./odin check examples/all -strict-style -vet -disallow-do
-      - name: Odin check vendor/sdl3
-        run: ./odin check vendor/sdl3  -strict-style -vet -disallow-do -no-entry-point
-      - name: Normal Core library tests
-        run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
-      - name: Optimized Core library tests
-        run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
-      - name: Vendor library tests
-        run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
-      - name: Internals tests
-        run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
-      - name: GitHub Issue tests
-        run: |
-          cd tests/issues
-          ./run.sh
-
-      - name: Run demo on WASI WASM32
-        run: |
-          ./odin build examples/demo -target:wasi_wasm32 -vet -strict-style -disallow-do -out:demo
-          wasmtime ./demo.wasm
-        if: matrix.os == 'macos-14'
-
-  build_ubuntu:
-    name: Ubuntu Build, Check, and Test
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v4
-      - name: Download LLVM
+      - name: Download LLVM (Ubuntu)
+        if: matrix.os == 'ubuntu-latest'
         run: |
         run: |
           wget https://apt.llvm.org/llvm.sh
           wget https://apt.llvm.org/llvm.sh
           chmod +x llvm.sh
           chmod +x llvm.sh
@@ -175,30 +133,44 @@ jobs:
       - name: Vendor library tests
       - name: Vendor library tests
         run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address
         run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address
       - name: Internals tests
       - name: Internals tests
-        run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
+        run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address
       - name: GitHub Issue tests
       - name: GitHub Issue tests
         run: |
         run: |
           cd tests/issues
           cd tests/issues
           ./run.sh
           ./run.sh
 
 
+      - name: Run demo on WASI WASM32
+        run: |
+          ./odin build examples/demo -target:wasi_wasm32 -vet -strict-style -disallow-do -out:demo
+          wasmtime ./demo.wasm
+        if: matrix.os == 'macos-14'
+
       - name: Check benchmarks
       - name: Check benchmarks
         run: ./odin check tests/benchmark -vet -strict-style -no-entry-point
         run: ./odin check tests/benchmark -vet -strict-style -no-entry-point
       - name: Odin check examples/all for Linux i386
       - name: Odin check examples/all for Linux i386
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_i386
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_i386
       - name: Odin check examples/all for Linux arm64
       - name: Odin check examples/all for Linux arm64
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_arm64
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_arm64
       - name: Odin check examples/all for FreeBSD amd64
       - name: Odin check examples/all for FreeBSD amd64
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64
       - name: Odin check examples/all for OpenBSD amd64
       - name: Odin check examples/all for OpenBSD amd64
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:openbsd_amd64
         run: ./odin check examples/all -vet -strict-style -disallow-do -target:openbsd_amd64
 
 
       - name: Odin check vendor/sdl3 for Linux i386
       - name: Odin check vendor/sdl3 for Linux i386
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:linux_i386
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:linux_i386
       - name: Odin check vendor/sdl3 for Linux arm64
       - name: Odin check vendor/sdl3 for Linux arm64
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:linux_arm64
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:linux_arm64
       - name: Odin check vendor/sdl3 for FreeBSD amd64
       - name: Odin check vendor/sdl3 for FreeBSD amd64
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:freebsd_amd64
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:freebsd_amd64
       - name: Odin check vendor/sdl3 for OpenBSD amd64
       - name: Odin check vendor/sdl3 for OpenBSD amd64
+        if: matrix.os == 'ubuntu-latest'
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:openbsd_amd64
         run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:openbsd_amd64
 
 
   build_windows:
   build_windows:

+ 1 - 0
base/runtime/internal.odin

@@ -1109,6 +1109,7 @@ __read_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uin
 
 
 when .Address in ODIN_SANITIZER_FLAGS {
 when .Address in ODIN_SANITIZER_FLAGS {
 	foreign {
 	foreign {
+		@(require)
 		__asan_unpoison_memory_region :: proc "system" (address: rawptr, size: uint) ---
 		__asan_unpoison_memory_region :: proc "system" (address: rawptr, size: uint) ---
 	}
 	}
 }
 }

+ 14 - 28
src/llvm_abi.cpp

@@ -977,7 +977,7 @@ namespace lbAbiAmd64SysV {
 			return types[0];
 			return types[0];
 		}
 		}
 
 
-		return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, sz == 0);
+		return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
 	}
 	}
 
 
 	gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
 	gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
@@ -1231,38 +1231,24 @@ namespace lbAbiArm64 {
 			}
 			}
 		} else {
 		} else {
 			i64 size = lb_sizeof(return_type);
 			i64 size = lb_sizeof(return_type);
-			if (size <= 16) {
-				LLVMTypeRef cast_type = nullptr;
-
-				if (size == 0) {
-					cast_type = LLVMStructTypeInContext(c, nullptr, 0, false);
-				} else if (size <= 8) {
-					cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8));
-				} else {
-					unsigned count = cast(unsigned)((size+7)/8);
-
-					LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64);
-					LLVMTypeRef *types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, count);
-
-					i64 size_copy = size;
-					for (unsigned i = 0; i < count; i++) {
-						if (size_copy >= 8) {
-							types[i] = llvm_i64;
-						} else {
-							types[i] = LLVMIntTypeInContext(c, 8*cast(unsigned)size_copy);
-						}
-						size_copy -= 8;
-					}
-					GB_ASSERT(size_copy <= 0);
-					cast_type = LLVMStructTypeInContext(c, types, count, true);
-				}
-				return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
-			} else {
+			if (size > 16) {
 				LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
 				LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
 
 
 				LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
 				LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
 				return lb_arg_type_indirect(return_type, attr);
 				return lb_arg_type_indirect(return_type, attr);
 			}
 			}
+
+			GB_ASSERT(size <= 16);
+			LLVMTypeRef cast_type = nullptr;
+			if (size == 0) {
+				cast_type = LLVMStructTypeInContext(c, nullptr, 0, false);
+			} else if (size <= 8) {
+				cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8));
+			} else {
+				LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64);
+				cast_type = LLVMArrayType2(llvm_i64, 2);
+			}
+			return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
 		}
 		}
 	}
 	}
     
     

+ 55 - 3
src/llvm_backend_general.cpp

@@ -2525,10 +2525,13 @@ general_end:;
 		}
 		}
 	}
 	}
 
 
-	src_size = align_formula(src_size, src_align);
-	dst_size = align_formula(dst_size, dst_align);
+	// NOTE(laytan): even though this logic seems sound, the Address Sanitizer does not
+	// want you to load/store the space of a value that is there for alignment.
+#if 0
+	i64 aligned_src_size = align_formula(src_size, src_align);
+	i64 aligned_dst_size = align_formula(dst_size, dst_align);
 
 
-	if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) {
+	if (LLVMIsALoadInst(val) && (aligned_src_size >= aligned_dst_size && src_align >= dst_align)) {
 		LLVMValueRef val_ptr = LLVMGetOperand(val, 0);
 		LLVMValueRef val_ptr = LLVMGetOperand(val, 0);
 		val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), "");
 		val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), "");
 		LLVMValueRef loaded_val = OdinLLVMBuildLoad(p, dst_type, val_ptr);
 		LLVMValueRef loaded_val = OdinLLVMBuildLoad(p, dst_type, val_ptr);
@@ -2536,8 +2539,57 @@ general_end:;
 		// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
 		// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
 
 
 		return loaded_val;
 		return loaded_val;
+	}
+#endif
+
+	if (src_size > dst_size) {
+		GB_ASSERT(p->decl_block != p->curr_block);
+		// NOTE(laytan): src is bigger than dst, need to memcpy the part of src we want.
+
+		LLVMValueRef val_ptr; 
+		if (LLVMIsALoadInst(val)) {
+			val_ptr = LLVMGetOperand(val, 0);
+		} else if (LLVMIsAAllocaInst(val)) {
+			val_ptr = LLVMBuildPointerCast(p->builder, val, LLVMPointerType(src_type, 0), "");
+		} else {
+			// NOTE(laytan): we need a pointer to memcpy from.
+			LLVMValueRef val_copy = llvm_alloca(p, src_type, src_align);
+			val_ptr = LLVMBuildPointerCast(p->builder, val_copy, LLVMPointerType(src_type, 0), "");
+			LLVMBuildStore(p->builder, val, val_ptr);
+		}
+
+		i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
+		max_align = gb_max(max_align, 16);
+
+		LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align);
+		LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(dst_type, 0), "");
+
+		LLVMTypeRef types[3] = {
+			lb_type(p->module, t_rawptr),
+			lb_type(p->module, t_rawptr),
+			lb_type(p->module, t_int)
+		};
+
+		LLVMValueRef args[4] = {
+			nptr,
+			val_ptr,
+			LLVMConstInt(LLVMIntTypeInContext(p->module->ctx, 8*cast(unsigned)build_context.int_size), dst_size, 0),
+			LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, 0),
+		};
+
+		lb_call_intrinsic(
+			p,
+			"llvm.memcpy.inline",
+			args,
+			gb_count_of(args),
+			types,
+			gb_count_of(types)
+		);
+
+		return OdinLLVMBuildLoad(p, dst_type, ptr);
 	} else {
 	} else {
 		GB_ASSERT(p->decl_block != p->curr_block);
 		GB_ASSERT(p->decl_block != p->curr_block);
+		GB_ASSERT(dst_size >= src_size);
 
 
 		i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
 		i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type));
 		max_align = gb_max(max_align, 16);
 		max_align = gb_max(max_align, 16);