let check_comparable op ev1 ev2 =
try
if not (Location_Bytes.is_included ev1 Location_Bytes.top_int)
|| not (Location_Bytes.is_included ev2 Location_Bytes.top_int)
then begin
let null_1, rest_1 = Location_Bytes.split Base.null ev1 in
let null_2, rest_2 = Location_Bytes.split Base.null ev2 in
let is_bottom1 = Location_Bytes.is_bottom rest_1 in
let is_bottom2 = Location_Bytes.is_bottom rest_2 in
(* First check if a non-zero integer is compared to an address *)
if ((not (Ival.is_included null_1 Ival.zero)) && (not is_bottom2))
|| ((not (Ival.is_included null_2 Ival.zero)) && (not is_bottom1))
then raise Not_found;
if not (is_bottom1 && is_bottom2)
then begin
let loc_bits1 = loc_bytes_to_loc_bits rest_1 in
let loc_bits2 = loc_bytes_to_loc_bits rest_2 in
let single_base_ok =
begin try
(* If they are both in the same base and both almost valid,
it's also fine, but beware of empty rest for comparisons
to NULL, or of function pointers *)
let extract_base is_bot loc =
if is_bot then Base.null
else begin
let base, offs = Location_Bits.find_lonely_key loc in
if Base.is_function base then
(if not (Ival.equal Ival.zero offs)
then raise Base.Not_valid_offset)
else
Base.is_valid_offset ~for_writing:false
Int.zero base offs;
base
end
in
let base_1 = extract_base is_bottom1 loc_bits1
and base_2 = extract_base is_bottom2 loc_bits2
in
is_bottom1 || is_bottom2 || (Base.equal base_1 base_2)
with
Not_found -> false
end
in
if not single_base_ok
then begin
if op = Eq || op = Ne
then begin
(* If both addresses are valid, they can be compared
for equality. *)
let loc1 = make_loc loc_bits1 Int_Base.one in
let loc2 = make_loc loc_bits2 Int_Base.one in
if (not (Locations.is_valid_or_function loc1)) ||
(not (Locations.is_valid_or_function loc2))
then raise Not_found;
(* But wait! literal strings can only be compared
if their contents are recognizably different!
(or the strings are physically the same) *)
Locations.Location_Bytes.iter_on_strings
~skip:None
(fun base1 s1 offs1 len1 ->
Locations.Location_Bytes.iter_on_strings
~skip:(Some base1)
(fun _ s2 offs2 len2 ->
let delta = offs1-offs2 in
begin
try
let start = if delta <= 0 then (-delta) else 0
in
for i = start to min len2 (len1 - delta)
do
(* Format.printf "%S %S %d %d@."
s1 s2 i delta; *)
if s2.[i] <> s1.[i + delta]
then raise Distinguishable_strings;
done;
raise Not_found
with Distinguishable_strings -> ();
end)
rest_1)
rest_2
end
else raise Not_found
end
end
end;
false, ev1, ev2
with Not_found | Base.Not_valid_offset ->
true, ev1, ev2