diff --git a/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilter.java b/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilter.java
index c24ecd1bc458599a0bf33634c0c26c911a83aa5d..c6482ea7f678f2d905c1a4953b2afca9d77fbfc8 100644
--- a/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilter.java
+++ b/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilter.java
@@ -148,7 +148,13 @@ public class SMGEdgeHasValueFilter {
   }
 
   public SMGEdgeHasValueFilter overlapsWith(SMGEdgeHasValue pEdge) {
+    assert object == null || object == pEdge.getObject()
+        : "cannot filter with a set object "
+            + object
+            + " and overlaps from a different object: "
+            + pEdge;
     SMGEdgeHasValueFilter filter = new SMGEdgeHasValueFilter(this);
+    filter.object = pEdge.getObject();
     filter.overlapsWith = pEdge;
     return filter;
   }
@@ -171,16 +177,8 @@ public class SMGEdgeHasValueFilter {
       return false;
     }
 
-    if (overlapsWith != null) {
-      if (!overlapsWith.getObject().equals(pEdge.getObject())) {
-        return false;
-      }
-      if (overlapsWith.getOffset() > pEdge.getOffset() + pEdge.getSizeInBits()) {
-        return false;
-      }
-      if (overlapsWith.getOffset() + overlapsWith.getSizeInBits() <= pEdge.getOffset()) {
-        return false;
-      }
+    if (overlapsWith != null && !overlapsWith.overlapsWith(pEdge)) {
+      return false;
     }
 
     if (sizeInBits >= 0 && sizeInBits != pEdge.getSizeInBits()) {
diff --git a/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilterTest.java b/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..536ae6ab4b62e1fb2f3c3472fa5049bca0fa3259
--- /dev/null
+++ b/src/org/sosy_lab/cpachecker/cpa/smg/graphs/edge/SMGEdgeHasValueFilterTest.java
@@ -0,0 +1,232 @@
+// This file is part of CPAchecker,
+// a tool for configurable software verification:
+// https://cpachecker.sosy-lab.org
+//
+// SPDX-FileCopyrightText: 2025 Dirk Beyer <https://www.sosy-lab.org>
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package org.sosy_lab.cpachecker.cpa.smg.graphs.edge;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.sosy_lab.cpachecker.cpa.smg.graphs.object.SMGObject;
+import org.sosy_lab.cpachecker.cpa.smg.graphs.object.SMGRegion;
+import org.sosy_lab.cpachecker.cpa.smg.graphs.value.SMGKnownSymValue;
+import org.sosy_lab.cpachecker.cpa.smg.graphs.value.SMGValue;
+import org.sosy_lab.cpachecker.cpa.smg.graphs.value.SMGZeroValue;
+
+public class SMGEdgeHasValueFilterTest {
+
+  private static final List<SMGEdgeHasValue> edges = new ArrayList<>();
+
+  static {
+    final List<SMGObject> objects = new ArrayList<>();
+    final SMGObject object1 = new SMGRegion(31, "a");
+    final SMGObject object4 = new SMGRegion(31, "a");
+    final SMGObject object2 = new SMGRegion(64, "b");
+    final SMGObject object3 = new SMGRegion(129, "c");
+    objects.add(object1);
+    objects.add(object4);
+    objects.add(object2);
+    objects.add(object3);
+
+    final SMGValue v0 = SMGZeroValue.INSTANCE;
+    final SMGValue v1 = SMGKnownSymValue.of();
+    final SMGValue v2 = SMGKnownSymValue.of();
+
+    final long bitstep = 8;
+
+    for (SMGObject object : objects) {
+      for (long offset = 0; offset < object.getSize(); offset += bitstep) {
+        for (long endOffset = offset + bitstep;
+            endOffset <= object.getSize();
+            endOffset += bitstep) {
+          long bitsize = endOffset - offset;
+          SMGEdgeHasValue hve0 = new SMGEdgeHasValue(bitsize, offset, object, v0);
+          SMGEdgeHasValue hve1 = new SMGEdgeHasValue(bitsize, offset, object, v1);
+          SMGEdgeHasValue hve2 = new SMGEdgeHasValue(bitsize, offset, object, v2);
+          edges.add(hve0);
+          edges.add(hve1);
+          edges.add(hve2);
+        }
+      }
+    }
+  }
+
+  private static void symmetricOverlaps(SMGEdgeHasValue pEdge1, SMGEdgeHasValue pEdge2) {
+    SMGEdgeHasValueFilter overlaps1 = new SMGEdgeHasValueFilter().overlapsWith(pEdge1);
+    SMGEdgeHasValueFilter overlaps2 = new SMGEdgeHasValueFilter().overlapsWith(pEdge2);
+
+    long ofs1 = pEdge1.getOffset();
+    long end1 = ofs1 + pEdge1.getSizeInBits();
+    long ofs2 = pEdge2.getOffset();
+    long end2 = ofs2 + pEdge2.getSizeInBits();
+
+    boolean areOverlapping =
+        pEdge1.getObject().equals(pEdge2.getObject())
+            && ((ofs1 <= ofs2 && ofs2 < end1) || (ofs2 <= ofs1 && ofs1 < end2));
+
+    String msg =
+        pEdge1 + " and " + pEdge2 + (areOverlapping ? " are" : " are not") + " overlapping";
+    assertWithMessage(msg).that(overlaps1.holdsFor(pEdge2)).isEqualTo(areOverlapping);
+    assertWithMessage(msg).that(overlaps2.holdsFor(pEdge1)).isEqualTo(areOverlapping);
+  }
+
+  private static void symmetricObjects(SMGEdgeHasValue pEdge1, SMGEdgeHasValue pEdge2) {
+    // TODO why different constructors...
+    SMGEdgeHasValueFilter f1 =
+        new SMGEdgeHasValueFilter().filterByObject(pEdge1.getObject()).filterWithoutSize();
+    SMGEdgeHasValueFilter f2 =
+        SMGEdgeHasValueFilter.objectFilter(pEdge2.getObject()).filterWithoutSize();
+
+    boolean haveSameObject = pEdge1.getObject().equals(pEdge2.getObject());
+    String msg =
+        pEdge1 + " and " + pEdge2 + (haveSameObject ? "" : " do not") + " have the same object";
+    assertWithMessage(msg).that(f1.holdsFor(pEdge2)).isEqualTo(haveSameObject);
+    assertWithMessage(msg).that(f2.holdsFor(pEdge1)).isEqualTo(haveSameObject);
+  }
+
+  private static void symmetricOffsets(SMGEdgeHasValue pEdge1, SMGEdgeHasValue pEdge2) {
+    SMGEdgeHasValueFilter f1 =
+        new SMGEdgeHasValueFilter().filterAtOffset(pEdge1.getOffset()).filterWithoutSize();
+    SMGEdgeHasValueFilter f2 =
+        new SMGEdgeHasValueFilter().filterAtOffset(pEdge2.getOffset()).filterWithoutSize();
+
+    boolean haveSameOffset = pEdge1.getOffset() == pEdge2.getOffset();
+    String msg =
+        pEdge1 + " and " + pEdge2 + (haveSameOffset ? "" : " do not") + " have the same offset";
+    assertWithMessage(msg).that(f1.holdsFor(pEdge2)).isEqualTo(haveSameOffset);
+    assertWithMessage(msg).that(f2.holdsFor(pEdge1)).isEqualTo(haveSameOffset);
+  }
+
+  private static void symmetricBitsizes(SMGEdgeHasValue pEdge1, SMGEdgeHasValue pEdge2) {
+    long bitsize1 = pEdge1.getSizeInBits();
+    long bitsize2 = pEdge2.getSizeInBits();
+    SMGEdgeHasValueFilter f1 = new SMGEdgeHasValueFilter().filterBySize(bitsize1);
+    SMGEdgeHasValueFilter f2 = new SMGEdgeHasValueFilter().filterBySize(bitsize2);
+
+    boolean haveSameBitsize = bitsize1 == bitsize2;
+    String msg =
+        pEdge1 + " and " + pEdge2 + (haveSameBitsize ? "" : " do not") + " have the same bitsize";
+
+    assertWithMessage(msg).that(f1.holdsFor(pEdge2)).isEqualTo(haveSameBitsize);
+    assertWithMessage(msg).that(f2.holdsFor(pEdge1)).isEqualTo(haveSameBitsize);
+  }
+
+  private static void asymmetricBitsizes(SMGEdgeHasValue pEdge1, SMGEdgeHasValue pEdge2) {
+    long bitsize1 = pEdge1.getSizeInBits();
+    long bitsize2 = pEdge2.getSizeInBits();
+    boolean isZero1 = pEdge1.getValue().isZero();
+    boolean isZero2 = pEdge2.getValue().isZero();
+
+    SMGEdgeHasValueFilter f1 = new SMGEdgeHasValueFilter().filterBySize(bitsize1);
+    SMGEdgeHasValueFilter f2 = new SMGEdgeHasValueFilter().filterBySize(bitsize2);
+
+    assertWithMessage(pEdge2 + " can contain " + bitsize1 + " bits")
+        .that(f1.holdsFor(pEdge2))
+        .isEqualTo(bitsize1 == bitsize2 || (isZero2 && bitsize1 <= bitsize2));
+    assertWithMessage(pEdge1 + " can contain " + bitsize2 + " bits")
+        .that(f2.holdsFor(pEdge1))
+        .isEqualTo(bitsize1 == bitsize2 || (isZero1 && bitsize2 <= bitsize1));
+  }
+
+  private static void symmetricValues(SMGEdgeHasValue pEdge1, SMGEdgeHasValue pEdge2) {
+    SMGValue value1 = pEdge1.getValue();
+    SMGValue value2 = pEdge2.getValue();
+    boolean areSameValue = value1.equals(value2);
+
+    SMGEdgeHasValueFilter f1 =
+        new SMGEdgeHasValueFilter().filterHavingValue(value1).filterWithoutSize();
+    SMGEdgeHasValueFilter f2 =
+        new SMGEdgeHasValueFilter().filterHavingValue(value2).filterWithoutSize();
+
+    String msg =
+        pEdge1 + " and " + pEdge2 + (areSameValue ? "" : " do not") + " have the same values";
+    assertWithMessage(msg).that(f1.holdsFor(pEdge2)).isEqualTo(areSameValue);
+    assertWithMessage(msg).that(f2.holdsFor(pEdge1)).isEqualTo(areSameValue);
+
+    SMGEdgeHasValueFilter f3 =
+        new SMGEdgeHasValueFilter().filterNotHavingValue(value1).filterWithoutSize();
+    SMGEdgeHasValueFilter f4 =
+        new SMGEdgeHasValueFilter().filterNotHavingValue(value2).filterWithoutSize();
+
+    assertWithMessage(msg).that(f3.holdsFor(pEdge2)).isEqualTo(!areSameValue);
+    assertWithMessage(msg).that(f4.holdsFor(pEdge1)).isEqualTo(!areSameValue);
+  }
+
+  @Test
+  public void symmetricTest() {
+    for (int i = 0; i < edges.size(); i++) {
+      for (int j = i + 1; j < edges.size(); j++) {
+        SMGEdgeHasValue edge1 = edges.get(i);
+        SMGEdgeHasValue edge2 = edges.get(j);
+        symmetricOverlaps(edge1, edge2);
+        symmetricObjects(edge1, edge2);
+        symmetricOffsets(edge1, edge2);
+        if (edge1.getValue().isZero() || edge2.getValue().isZero()) {
+          asymmetricBitsizes(edge1, edge2);
+        } else {
+          symmetricBitsizes(edge1, edge2);
+        }
+        symmetricValues(edge1, edge2);
+      }
+    }
+  }
+
+  @Test
+  public void reflexiveTest() {
+    for (SMGEdgeHasValue hve : edges) {
+      // overlap
+      assertWithMessage(hve + " is overlapping itself")
+          .that(new SMGEdgeHasValueFilter().overlapsWith(hve).holdsFor(hve))
+          .isTrue();
+
+      // object TODO why different constructors...
+      assertWithMessage(hve + " has the same object as itself")
+          .that(
+              new SMGEdgeHasValueFilter()
+                  .filterByObject(hve.getObject())
+                  .filterWithoutSize()
+                  .holdsFor(hve))
+          .isTrue();
+      assertWithMessage(hve + " has the same object as itself")
+          .that(
+              SMGEdgeHasValueFilter.objectFilter(hve.getObject()).filterWithoutSize().holdsFor(hve))
+          .isTrue();
+
+      // offset
+      assertWithMessage(hve + " has the same offset as itself")
+          .that(
+              new SMGEdgeHasValueFilter()
+                  .filterAtOffset(hve.getOffset())
+                  .filterWithoutSize()
+                  .holdsFor(hve))
+          .isTrue();
+
+      // bitsize
+      assertWithMessage(hve + " has the same bitsize as itself")
+          .that(new SMGEdgeHasValueFilter().filterBySize(hve.getSizeInBits()).holdsFor(hve))
+          .isTrue();
+
+      // value
+      assertWithMessage(hve + " has the same value as itself")
+          .that(
+              new SMGEdgeHasValueFilter()
+                  .filterHavingValue(hve.getValue())
+                  .filterWithoutSize()
+                  .holdsFor(hve))
+          .isTrue();
+      assertWithMessage(hve + " has the same value as itself")
+          .that(
+              new SMGEdgeHasValueFilter()
+                  .filterNotHavingValue(hve.getValue())
+                  .filterWithoutSize()
+                  .holdsFor(hve))
+          .isFalse();
+    }
+  }
+}