]> granicus.if.org Git - graphviz/commit
gvpr: fix: wrap members needing cleanup in a struct and outline
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Sun, 28 Aug 2022 03:04:07 +0000 (20:04 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Tue, 30 Aug 2022 14:55:43 +0000 (07:55 -0700)
commit64ee6634688d8a49d302b839d6308e2e3a410cbe
tree5ba77e955a7f8c87e59d4e21511328b0161b4a8c
parent564f0b0e19a3b638ec00e44b2fbed84bb486e0fc
gvpr: fix: wrap members needing cleanup in a struct and outline

When seeing this code, the compiler emitted numerous warnings like:

  gvpr.c: In function ‘gvpr’:
  gvpr.c:929:17: warning: variable ‘prog’ might be clobbered by
    ‘longjmp’ or ‘vfork’ [-Wclobbered]
       parse_prog *prog = 0;
                   ^~~~

What it is trying to tell us is that this code violates the assumptions of
`setjmp`/`longjmp`. Referencing any non-volatile stack-allocated variable after
a `longjmp` is undefined behavior.¹

This change extracts all the members that need to be referenced after `longjmp`
into a wrapper function. This basically puts a function call boundary in a place
such that the code no longer violates assumptions of the C standard. It is a
little awkward that we have to do this by hand, as the transformation is
mechanical and the compiler technically has enough information to do this for
us. But `setjmp`/`longjmp` come from the old world and are low level mechanisms.
If the compiler sees a call to them, it assumes you are doing something unusual
and want to do it exactly as you wrote.

While making this adjustment, some white space is adjusted and some coercion to
boolean is changed to explicit comparisons against `NULL`.

I do not understand why, but after this change the compiler still believes
`nextg` can be clobbered by a `longjmp`. While this is true, `nextg` is not used
after `longjmp`-ing back to `gvpr_core`, so I do not know why the compiler
thinks it needs to warn us about this.

Gitlab: #1801

¹ This restriction stems from how `setjmp`/`longjmp` work on certain platforms.
  If a variable is live in a register instead of on the stack, it is not
  guaranteed to be restored during a `longjmp`. Hence why the value of such
  variables is undefined after a `longjmp`.
lib/gvpr/gvpr.c