list: Fix pointer math bug

Change-Id: Ic176d7401d99aa143edf41fe3ca65412ef42ec19
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/maize/+/265654
Pigweed-Auto-Submit: Erik Gilling <konkers@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Travis Geiselbrecht <travisg@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
diff --git a/lib/list/list.rs b/lib/list/list.rs
index 93578d5..f09f9f0 100644
--- a/lib/list/list.rs
+++ b/lib/list/list.rs
@@ -163,15 +163,15 @@
 
     unsafe fn get_link_ptr(element: &T) -> NonNull<Link> {
         let element_ptr: NonNull<Link> = core::mem::transmute::<&T, NonNull<Link>>(element);
-        element_ptr.byte_sub(A::LINK_OFFSET)
+        element_ptr.byte_add(A::LINK_OFFSET)
     }
 
     unsafe fn get_element_ptr(link: NonNull<Link>) -> *const T {
-        link.byte_add(A::LINK_OFFSET).as_ptr() as *const T
+        link.byte_sub(A::LINK_OFFSET).as_ptr() as *const T
     }
 
     unsafe fn get_element_mut(link: NonNull<Link>) -> *mut T {
-        link.byte_add(A::LINK_OFFSET).as_ptr() as *mut T
+        link.byte_sub(A::LINK_OFFSET).as_ptr() as *mut T
     }
 
     /// unchecked means we don't `assert!((*element_ptr.as_ptr()).is_unlinked());`
diff --git a/lib/list/tests/list_test.rs b/lib/list/tests/list_test.rs
index 676d6aa..2649d36 100644
--- a/lib/list/tests/list_test.rs
+++ b/lib/list/tests/list_test.rs
@@ -19,6 +19,11 @@
 use list::*;
 use unittest::test;
 
+// `#[repr(C)]` is used to ensure that `link` is at a non-zero offset.
+// Previously, without this, the compiler was putting link at the beginning of
+// the struct causing `LINK_OFFSET` in the adapter to be zero which obfuscated
+// some pointer math bugs.
+#[repr(C)]
 struct TestMember {
     value: u32,
     link: Link,