.include common

#node is a potential null derefeerence
null_deref( n:node )

#expression has pointer type
ptr_exp( e:node )

#expression may have null value
maybe_null_e( e:node )

#variable may be null at target node
maybe_null_var( v:node, t:node )

#path from s to t without having v in a conditional
path_without_check( s:node, t:node, v:node )

#path from s to t without having v in a conditional
cfg_path_nocheck( s:node, si:number, t:node, ti:number, v:node )

#symbol v is used in node c
symbol_used( v:node, c:node )

ptr_exp( e ) :- expType( e, t ), ptrT( t, _ ).

maybe_null_e( e ) :- ptr_exp(e), callE( e, _ ).
maybe_null_e( e ) :- maybe_null_e(s), castE(e,s).
maybe_null_e( e ) :- ptr_exp(e), varE(e,v), maybe_null_var(v,e).
maybe_null_e( e ) :- ptr_exp(e), addE(e,l,_), maybe_null_e(l).
maybe_null_e( e ) :- ptr_exp(e), anyAssignE(e,_,r), maybe_null_e(r).

#variable v might be null at target node
maybe_null_var( v, t ) :- \
    anyAssignE(t,l,r), varE(l,v), maybe_null_e(r).
maybe_null_var( v, t ) :- \
    maybe_null_var( v, s ), \
    cfg_path_nocheck( s, 0, t, 0, v).

cfg_path_nocheck( s, si, t, ti, _ ) :- s=t, si=ti.
cfg_path_nocheck( s, si, t, ti, _ ) :- cfgNext( s, si, t, ti ).
cfg_path_nocheck( s, si, t, ti, v ) :- \
    cfgNext( s, si, m, mi ), \
    !ifS(m,*,*,*), \
    cfg_path_nocheck( m, mi, t, ti, v ).
cfg_path_nocheck( s, si, t, ti, v ) :- \
    cfgNext( s, si, m, mi ), \
    ifS(m,c,_,_), \
    !symbol_used( v, c ), \
    cfg_path_nocheck( m, mi, t, ti, v ).

symbol_used( v, c ) :- \
    varE( e, v ), \
    anc( c, e ).
 
null_deref( n ) :- maybe_null_e(e), ptrDerefE( m, e ), parent( n, m ).
null_deref( n ) :- maybe_null_e(e), arraySubscriptE( m, e, _ ), parent( n, m ).
null_deref( n ) :- maybe_null_e(e), arrowE( m, e, _ ), parent( n, m ).

null_deref( N )?
