ocaml.lang.best-practice.exception.bad-reraise

profile photo of semgrepsemgrep
Author
unknown
Download Count*

You should not re-raise exceptions using 'raise' because it loses track of where the exception was raised originally, leading to a useless and possibly confusing stack trace. Instead, you should obtain a stack backtrace as soon as the exception is caught using 'try ... with exn -> let trace = Printexc.get_raw_backtrace () in ...', and keep it around until you re-raise the exception using 'Printexc.raise_with_backtrace exn trace'. You must collect the stack backtrace before calling another function which might internally raise and catch exceptions. To avoid false positives from Semgrep, write 'raise (Foo args)' instead of 'let e = Foo args in raise e'.

Run Locally

Run in CI

Defintion

rules:
  - id: bad-reraise
    patterns:
      - pattern: |
          raise $EXN
      - metavariable-regex:
          metavariable: $EXN
          regex: \A[a-z_][a-z_A-Z0-9']*\z
    message: You should not re-raise exceptions using 'raise' because it loses track
      of where the exception was raised originally, leading to a useless and
      possibly confusing stack trace. Instead, you should obtain a stack
      backtrace as soon as the exception is caught using 'try ... with exn ->
      let trace = Printexc.get_raw_backtrace () in ...', and keep it around
      until you re-raise the exception using 'Printexc.raise_with_backtrace exn
      trace'. You must collect the stack backtrace before calling another
      function which might internally raise and catch exceptions. To avoid false
      positives from Semgrep, write 'raise (Foo args)' instead of 'let e = Foo
      args in raise e'.
    languages:
      - ocaml
    severity: WARNING
    metadata:
      category: best-practice
      technology:
        - ocaml
      references:
        - https://v2.ocaml.org/api/Printexc.html
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

exception.ml

let () =
  try ()
  with exn ->
    (* ruleid:bad-reraise *)
    raise exn

let () =
  match () with
  | Foo _ ->
      raise Not_found
  | _ as _exn2' ->
      (* ruleid:bad-reraise *)
      raise _exn2'

let () =
  raise (Error "uh oh")

let () =
  raise Exit

(* false positive *)
let () =
  let e = Foo args in
  (* ruleid:bad-reraise *)
  raise e

(* no longer a false positive *)
let () =
  raise (Foo args)