Skip to content
  • Taylor Blau's avatar
    string-list: introduce `string_list_setlen()` · 492ba813
    Taylor Blau authored and Junio C Hamano's avatar Junio C Hamano committed
    
    
    It is sometimes useful to reduce the size of a `string_list`'s list of
    items without having to re-allocate them. For example, doing the
    following:
    
        struct strbuf buf = STRBUF_INIT;
        struct string_list parts = STRING_LIST_INIT_NO_DUP;
        while (strbuf_getline(&buf, stdin) != EOF) {
          parts.nr = 0;
          string_list_split_in_place(&parts, buf.buf, ":", -1);
          /* ... */
        }
        string_list_clear(&parts, 0);
    
    is preferable over calling `string_list_clear()` on every iteration of
    the loop. This is because `string_list_clear()` causes us free our
    existing `items` array. This means that every time we call
    `string_list_split_in_place()`, the string-list internals re-allocate
    the same size array.
    
    Since in the above example we do not care about the individual parts
    after processing each line, it is much more efficient to pretend that
    there aren't any elements in the `string_list` by setting `list->nr` to
    0 while leaving the list of elements allocated as-is.
    
    This allows `string_list_split_in_place()` to overwrite any existing
    entries without needing to free and re-allocate them.
    
    However, setting `list->nr` manually is not safe in all instances. There
    are a couple of cases worth worrying about:
    
      - If the `string_list` is initialized with `strdup_strings`,
        truncating the list can lead to overwriting strings which are
        allocated elsewhere. If there aren't any other pointers to those
        strings other than the ones inside of the `items` array, they will
        become unreachable and leak.
    
        (We could ourselves free the truncated items between
        string_list->items[nr] and `list->nr`, but no present or future
        callers would benefit from this additional complexity).
    
      - If the given `nr` is larger than the current value of `list->nr`,
        we'll trick the `string_list` into a state where it thinks there are
        more items allocated than there actually are, which can lead to
        undefined behavior if we try to read or write those entries.
    
    Guard against both of these by introducing a helper function which
    guards assignment of `list->nr` against each of the above conditions.
    
    Co-authored-by: default avatarJeff King <peff@peff.net>
    Signed-off-by: default avatarJeff King <peff@peff.net>
    Signed-off-by: default avatarTaylor Blau <me@ttaylorr.com>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
    492ba813