aboutsummaryrefslogblamecommitdiffstats
path: root/lib/crypto/c_src/check_erlang.cocci
blob: b2a981f2ac4101d94f1517f9611d6dd1f80ce116 (plain) (tree)






























                                                                           
               








                                                
         
                                 




















































                                                                                
                                                                                                                                                                                                     






































                                                                                                                                                                                                                                                                                                                                                                                            

                        
                                                                                                               












                  















                                                                                                                                                                                                                               
                                                                                                                                                                                                     










                                                                                                                                                                                                                                                                                                                                                                                            
                                                                                                               
                                                                                         
 









                     

                     
 
// %CopyrightBegin%
//
// Copyright Doug Hogan 2019. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// %CopyrightEnd%

// Coccinelle script to help verify Erlang calls.
// http://coccinelle.lip6.fr
// https://github.com/coccinelle/coccinelle
//
// These work with the Erlang code because it has a rigid coding pattern.
// $ spatch.opt --all-includes -sp_file check_erlang.cocci -dir .

// Make sure resources are cleaned up properly in all paths.
// Need 'strict' so it's also checked in error handling paths.
@enif_alloc_resource@
type T;
identifier CTX, L;
identifier virtual.enif_alloc_resource, virtual.enif_release_resource;
position p, pr;
@@

 T *CTX = NULL;

 ...
 if ((CTX = enif_alloc_resource(...)@p) == NULL)
   goto L;

 ... when strict, forall
 if (CTX)
   enif_release_resource(CTX)@pr;


// After calling enif_alloc_binary(), you must either release it with
// enif_release_binary() or transfer ownership to Erlang via enif_make_binary().
@enif_alloc_binary@
expression SZ;
identifier BIN, RET, ENV, X, L;
identifier TUPLE =~ "^enif_make_tuple[0-9]+$";
identifier virtual.enif_alloc_binary, virtual.enif_make_binary;
identifier virtual.enif_release_binary;
position pa, pm, pr;
@@

// This construct is used in engine.c
(
  if (!enif_alloc_binary(SZ, &BIN)@pa)
      goto L;

  ... when strict, forall
  return
(
  enif_make_binary(ENV, &BIN)@pm
|
  TUPLE(..., enif_make_binary(ENV, &BIN)@pm)@pm
);

|
// This is the typical way we allocate and use binaries.
  int X = 0;

  ...
  if (!enif_alloc_binary(SZ, &BIN)@pa)
    goto L;
  X = 1;

  ... when strict, forall
(
  RET = enif_make_binary(ENV, &BIN)@pm;
  X = 0;
|
  if (X)
    enif_release_binary(&BIN)@pr;
|
  return enif_make_binary(ENV, &BIN)@pm;
)
)

// TODO: These don't have single checks that handle all cases.
//
// enif_consume_timeslice      returns 1 if exhausted or else 0
// enif_has_pending_exception  returns true if exception pending

@erlang_check_void@
identifier FUNCVOID =~ "^(enif_mutex_destroy|enif_mutex_lock|enif_mutex_unlock|enif_rwlock_destroy|enif_rwlock_rlock|enif_rwlock_runlock|enif_rwlock_rwlock|enif_rwlock_rwunlock|enif_system_info)$";
position p;
@@

  FUNCVOID(...)@p;


@erlang_check_null@
expression X;
identifier L;
identifier FUNCNULL =~ "^(enif_alloc|enif_alloc_resource|enif_dlopen|enif_dlsym|enif_make_new_binary|enif_mutex_create|enif_open_resource_type|enif_realloc|enif_rwlock_create)$";
position p;
@@

(
  if ((X = FUNCNULL(...)@p) == NULL)
      goto L;
|
  X = FUNCNULL(...)@p;
  if (X == NULL)
      goto L;
|
  return FUNCNULL(...)@p;
)


@erlang_check_not@
identifier L;
identifier FUNCNOT =~ "^(enif_alloc_binary|enif_get_int|enif_get_list_cell|enif_get_list_length|enif_get_long|enif_get_map_value|enif_get_resource|enif_get_tuple|enif_get_uint|enif_get_ulong|enif_inspect_binary|enif_inspect_iolist_as_binary|enif_is_atom|enif_is_binary|enif_is_current_process_alive|enif_is_empty_list|enif_is_list|enif_is_map|enif_is_tuple|enif_realloc_binary)$";
position p;
@@

(
  if (!FUNCNOT(...)@p)
      goto L;
|
  return FUNCNOT(...)@p;
)


@erlang_check_null_free@
expression X;
identifier FUNCFREE =~ "^(enif_free|enif_free_env|enif_free_iovec|enif_release_binary|enif_release_resource)$";
position p;
@@

  if (
(
 X
|
 X != NULL
)
  )
    FUNCFREE(X)@p;


@erlang_check_new@
expression RET;
identifier FUNCNEW =~ "^(enif_make_atom|enif_make_badarg|enif_make_binary|enif_make_int|enif_make_list|enif_make_list_from_array|enif_make_resource|enif_make_tuple|enif_raise_exception|enif_schedule_nif|enif_thread_self)$";
position p;
@@

(
  RET = FUNCNEW(...)@p;
|
  return FUNCNEW(...)@p;
)


// Flag any calls that aren't part of the above pattern.
@enif_alloc_not_free@

identifier FUNCVOID =~ "^(enif_mutex_destroy|enif_mutex_lock|enif_mutex_unlock|enif_rwlock_destroy|enif_rwlock_rlock|enif_rwlock_runlock|enif_rwlock_rwlock|enif_rwlock_rwunlock|enif_system_info)$";
position pvoid != {erlang_check_void.p,enif_alloc_binary.pr};

identifier FUNCNULL =~ "^(enif_alloc|enif_alloc_resource|enif_dlopen|enif_dlsym|enif_make_new_binary|enif_mutex_create|enif_open_resource_type|enif_realloc|enif_rwlock_create)$";
position pnull != {erlang_check_null.p,enif_alloc_resource.p};

identifier FUNCNOT =~ "^(enif_alloc_binary|enif_get_int|enif_get_list_cell|enif_get_list_length|enif_get_long|enif_get_map_value|enif_get_resource|enif_get_tuple|enif_get_uint|enif_get_ulong|enif_inspect_binary|enif_inspect_iolist_as_binary|enif_is_atom|enif_is_binary|enif_is_current_process_alive|enif_is_empty_list|enif_is_list|enif_is_map|enif_is_tuple|enif_realloc_binary)$";
position pnot != {erlang_check_not.p,enif_alloc_binary.pa};

identifier FUNCNEW =~ "^(enif_make_atom|enif_make_badarg|enif_make_binary|enif_make_int|enif_make_list|enif_make_list_from_array|enif_make_resource|enif_make_tuple|enif_raise_exception|enif_schedule_nif|enif_thread_self)$";
position pnew != {erlang_check_new.p,enif_alloc_binary.pm};

identifier FUNCFREE =~ "^(enif_free|enif_free_env|enif_free_iovec|enif_release_binary|enif_release_resource)$";
position pfree != {enif_alloc_resource.pr,enif_alloc_binary.pr,erlang_check_null_free.p};

@@

(
* FUNCVOID(...)@pvoid
|
* FUNCNULL(...)@pnull
|
* FUNCNOT(...)@pnot
|
* FUNCNEW(...)@pnew
|
* FUNCFREE(...)@pfree
)