@ -56,47 +56,74 @@ let immediate_or_first_call calling_context (trace : Trace.t) =
let get_message diagnostic =
let get_message diagnostic =
let pulse_start_msg = " Pulse found a potential " in
let pulse_start_msg = " Pulse found a potential " in
match diagnostic with
match diagnostic with
| AccessToInvalidAddress { calling_context ; invalidation_trace ; access_trace } ->
| AccessToInvalidAddress { calling_context ; invalidation ; invalidation_trace ; access_trace } -> (
(* The goal is to get one of the following messages depending on the scenario:
match invalidation with
| ConstantDereference i when IntLit . equal i IntLit . zero ->
(* Special error message for nullptr dereference *)
let pp_access_trace fmt ( trace : Trace . t ) =
match immediate_or_first_call calling_context trace with
| ` Immediate ->
()
| ` Call f ->
F . fprintf fmt " in call to %a " CallEvent . describe f
in
let pp_invalidation_trace line fmt ( trace : Trace . t ) =
let pp_line fmt line = F . fprintf fmt " on line %d " line in
match immediate_or_first_call calling_context trace with
| ` Immediate ->
F . fprintf fmt " null pointer dereference %a " pp_line line
| ` Call f ->
F . fprintf fmt " null pointer dereference %a indirectly during the call to %a " pp_line
line CallEvent . describe f
in
let invalidation_line =
let { Location . line ; _ } = Trace . get_outer_location invalidation_trace in
line
in
F . asprintf " %s %a%a. " pulse_start_msg
( pp_invalidation_trace invalidation_line )
invalidation_trace pp_access_trace access_trace
| _ ->
(* The goal is to get one of the following messages depending on the scenario:
42 : delete x ; return x -> f
42 : delete x ; return x -> f
" `x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x` "
" `x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x` "
42 : bar ( x ) ; return x -> f
42 : bar ( x ) ; return x -> f
" `x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x` in call to `bar` "
" `x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x` in call to `bar` "
42 : bar ( x ) ; foo ( x ) ;
42 : bar ( x ) ; foo ( x ) ;
" call to `foo` eventually accesses `x->f` but `x` was invalidated at line 42 by `delete` on `x` in call to `bar` "
" call to `foo` eventually accesses `x->f` but `x` was invalidated at line 42 by `delete` on `x` in call to `bar` "
If we don't have " x->f " but instead some non - user - visible expression , then
If we don't have " x->f " but instead some non - user - visible expression , then
" access to `x`, which was invalidated at line 42 by `delete` on `x` "
" access to `x`, which was invalidated at line 42 by `delete` on `x` "
Likewise if we don't have " x " in the second part but instead some non - user - visible expression , then
Likewise if we don't have " x " in the second part but instead some non - user - visible expression , then
" `x->f` accesses `x`, which was invalidated at line 42 by `delete` "
" `x->f` accesses `x`, which was invalidated at line 42 by `delete` "
* )
* )
let pp_access_trace fmt ( trace : Trace . t ) =
let pp_access_trace fmt ( trace : Trace . t ) =
match immediate_or_first_call calling_context trace with
match immediate_or_first_call calling_context trace with
| ` Immediate ->
| ` Immediate ->
()
F . fprintf fmt " accessing memory that "
| ` Call f ->
| ` Call f ->
F . fprintf fmt " in call to %a " CallEvent . describe f
F . fprintf fmt " call to %a eventually accesses memory that " CallEvent . describe f
in
in
let pp_invalidation_trace line fmt ( trace : Trace . t ) =
let pp_invalidation_trace line invalidation fmt ( trace : Trace . t ) =
let pp_line fmt line = F . fprintf fmt " on line %d " line in
let pp_line fmt line = F . fprintf fmt " on line %d " line in
match immediate_or_first_call calling_context trace with
match immediate_or_first_call calling_context trace with
| ` Immediate ->
| ` Immediate ->
F . fprintf fmt " null pointer dereference %a" pp_line line
F . fprintf fmt " %a%a" Invalidation . describe invalidation pp_line line
| ` Call f ->
| ` Call f ->
F . fprintf fmt " null pointer dereference %a indirectly during the call to %a" pp_lin e
F . fprintf fmt " %a%a indirectly during the call to %a" Invalidation . describ e
line CallEvent . describe f
invalidation pp_line line CallEvent . describe f
in
in
let invalidation_line =
let invalidation_line =
let { Location . line ; _ } = Trace . get_outer_location invalidation_trace in
let { Location . line ; _ } = Trace . get_outer_location invalidation_trace in
line
line
in
in
F . asprintf " % s %a%a." pulse_start_msg
F . asprintf " % a%a" pp_access_trace access_trace
( pp_invalidation_trace invalidation_line )
( pp_invalidation_trace invalidation_line invalidation )
invalidation_trace pp_access_trace access_trace
invalidation_trace )
| MemoryLeak { procname ; location ; allocation_trace } ->
| MemoryLeak { procname ; location ; allocation_trace } ->
let allocation_line =
let allocation_line =
let { Location . line ; _ } = Trace . get_outer_location allocation_trace in
let { Location . line ; _ } = Trace . get_outer_location allocation_trace in