On 5/3/21 10:12 PM, Elijah Newren via GitGitGadget wrote: > From: Elijah Newren <newren@xxxxxxxxx> > > Previously, callers of the merge-ort API could have passed an > uninitialized value for struct merge_result *result. However, we want > to check result to see if it has cached renames from a previous merge > that we can reuse; such values would be found behind result->priv. > However, if result->priv is uninitialized, attempting to access behind > it will give a segfault. So, we need result->priv to be NULL (which > will be the case if the caller does a memset(&result, 0)), or be written > by a previous call to the merge-ort machinery. Documenting this > requirement may help, but despite being the person who introduced this > requirement, I still missed it once and it did not fail in a very clear > way and led to a long debugging session. I empathize with your frustration here. > Add a _properly_initialized field to merge_result; that value will be > 0 if the caller zero'ed the merge_result, it will be set to a very > specific value by a previous run by the merge-ort machinery, and if it's > uninitialized it will most likely either be 0 or some value that does > not match the specific one we'd expect allowing us to throw a much more > meaningful error. This approach is an interesting pattern to follow for future efforts, too. > +static unsigned RESULT_INITIALIZED = 0x1abe11ed; /* unlikely accidental value */ > + > struct traversal_callback_data { > unsigned long mask; > unsigned long dirmask; > @@ -3746,6 +3748,10 @@ static void merge_start(struct merge_options *opt, struct merge_result *result) > assert(opt->obuf.len == 0); > > assert(opt->priv == NULL); > + if (result->_properly_initialized != 0 && > + result->_properly_initialized != RESULT_INITIALIZED) > + BUG("struct merge_result passed to merge_incore_*recursive() must be zeroed or filled with values from a previous run"); > + assert(!!result->priv == !!result->_properly_initialized); > if (result->priv) { > opt->priv = result->priv; > result->priv = NULL; > @@ -3905,6 +3911,7 @@ static void merge_ort_nonrecursive_internal(struct merge_options *opt, > result->clean &= strmap_empty(&opt->priv->conflicted); > if (!opt->priv->call_depth) { > result->priv = opt->priv; > + result->_properly_initialized = RESULT_INITIALIZED; > opt->priv = NULL; > } > } > diff --git a/merge-ort.h b/merge-ort.h > index d53a0a339f33..c011864ffeb1 100644 > --- a/merge-ort.h > +++ b/merge-ort.h > @@ -29,6 +29,8 @@ struct merge_result { > * !clean) and to print "CONFLICT" messages. Not for external use. > */ > void *priv; > + /* Also private */ > + unsigned _properly_initialized; > }; Will work as intended. Thank you for reducing developer friction. Thanks, -Stolee