A heightfield is defined as a raster of heights. That means that it's not possible to have overhangs (it's one of the major drawbacks of heightfields). Consider the worst case: on sample at the minimum value and its neighbor at the maximum. If you trace contours using an interpolating checker, then every possible contour will pass between those two samples, each slightly offset from the next. If you use a contour tracer that's locked to pixel values, half of them will hit one pixel and half will hit the other pixel.

Now think about what a contour is: it is the edge of a constant-height surface If you pull out one contour and draw it as a filled element in white on a black background, then you should get exactly the same image as if you drew your original surface colored with all pixels at or above your contour level in white and all pixels below that in black. The contours are effectively slices of the surface. If you're getting interior holes in your contours, then you have basins. You have a basin-fill algorithm and a raster, which means the next part is pretty straightforward (if a bit inelegant): fill all basins in a temp surface and generate contours. These are the base contours and have no basins. Now make a temp surface that's just the basin deltas adjusted for the base level in the same way as the water surface I discussed before. Contouring that surface from low to high will produce contours that are children of the base contours. Then scan the water surface on top of that.

Note that it's a whole lot easier if you have polypolygons (polygons with others that punch out holes) available as a primitive. In that case, you just scan all of the polygons as a given height and the polypoly renderer does the grunt work.