Skip to content

Add wrappers for malloc, realloc with a calloc-like interface#2006

Open
daviesrob wants to merge 3 commits into
samtools:developfrom
daviesrob:hts_alloc
Open

Add wrappers for malloc, realloc with a calloc-like interface#2006
daviesrob wants to merge 3 commits into
samtools:developfrom
daviesrob:hts_alloc

Conversation

@daviesrob
Copy link
Copy Markdown
Member

Help avoid bugs due to integer wrap-around when calculating sizes to pass to malloc() or realloc(). calloc() is better in this respect as it takes two parameters (number and size) and catches overflows when multiplying them together. The new interfaces provide similar functions for malloc() and realloc(), along with additional ones to handle cases that commonly occur in the code base.

All the functions are static inlines, so it should be possible for the optimiser to simplify the code in the cases where overflow cannot occur (for example, due to the size of the data types actually being passed in).

The interfaces are:

  • Saturating arithmetic

    Primitives used to build the later functions.

    • hts_add_sat2(a, b) returns (a + b) or SIZE_MAX on overflow

    • hts_add_sat3(a, b, c) returns (a + b + c) or SIZE_MAX on overflow

    • hts_prod_sat2(a, b) returns (a * b) or SIZE_MAX on overflow

  • Wrappers around malloc()

    • hts_malloc(size_t size)
      For use with the saturating arithmetic functions above. Catches over-large allocations before they get to malloc(). Prevents spurious gcc warnings about very large allocations, and allows the optimiser to convert the overflow cases to an early exit.

    • hts_malloc_p(size_t a, size_t b)
      Replaces malloc(a * b)

    • hts_malloc_ps(size_t sz, size_t a, size_t b)
      Replaces malloc(sz * (a + b))

    • hts_malloc_pse(size_t sz, size_t a, size_t b, size_t extra)
      Replaces malloc(sz * (a + b) + extra)

  • Wrappers around calloc()

    • hts_calloc(size_t size, size_t num)
      For use with the saturating arithmetic functions above. Catches over-large allocations before they get to calloc(). Prevents spurious gcc warnings about very large allocations, and allows the optimiser to convert the overflow cases to an early exit.

    • hts_calloc_ps(size_t sz, size_t a, size_t b)
      Replaces calloc(a + b, sz)

    • hts_calloc_pse(size_t sz, size_t a, size_t b, size_t extra)
      Replaces calloc(sz * (a + b) + extra, 1)

  • Wrappers around realloc()

    • hts_realloc(void *orig, size_t size)
      For use with the saturating arithmetic functions above. Catches over-large allocations before they get to realloc(). Prevents spurious gcc warnings about very large allocations, and allows the optimiser to convert the overflow cases to an early exit.

    • hts_realloc_p(void *orig, size_t a, size_t b)
      Replaces realloc(orig, a * b)

    • hts_realloc_ps(void *orig, size_t sz, size_t a, size_t b)
      Replaces realloc(orig, sz * (a + b))

    • hts_realloc_pse(void *orig, size_t sz, size_t a, size_t b, size_t extra)
      Replaces realloc(orig, sz * (a + b) + extra)

The new interfaces are applied to the existing code where appropriate. To keep the changes simple, no attempt is made here to fix issues around handling NULL returns. Such fixes will be done in a future update.

daviesrob added 3 commits May 11, 2026 10:15
Help avoid bugs due to integer wrap-around when calculating
sizes to pass to malloc() or realloc().  calloc() is better
in this respect as it takes two parameters (number and size)
and catches overflows when multiplying them together.  The
new interfaces provide similar functions for malloc() and
realloc(), along with additional ones to handle cases that
commonly occur in the code base.

All the functions are static inlines, so it should be
possible for the optimiser to simplify the code in
the cases where overflow cannot occur (for example,
due to the size of the data types actually being
passed in).

The interfaces are:

* Saturating arithmetic

  Primitives used to build the later functions.

  - hts_add_sat2(a, b) returns (a + b) or SIZE_MAX on
    overflow

  - hts_add_sat3(a, b, c) returns (a + b + c) or SIZE_MAX
    on overflow

  - hts_prod_sat2(a, b) returns (a * b) or SIZE_MAX on
    overflow

* Wrappers around malloc()

  - hts_malloc(size_t size)
    For use with the saturating arithmetic functions
    above.  Catches over-large allocations before they get
    to malloc().  Prevents spurious gcc warnings about
    very large allocations, and allows the optimiser
    to convert the overflow cases to an early exit.

  - hts_malloc_p(size_t a, size_t b)
    Replaces malloc(a * b)

  - hts_malloc_ps(size_t sz, size_t a, size_t b)
    Replaces malloc(sz * (a + b))

  - hts_malloc_pse(size_t sz, size_t a, size_t b, size_t extra)
    Replaces malloc(sz * (a + b) + extra)

* Wrappers around calloc()

  - hts_calloc(size_t size, size_t num)
    For use with the saturating arithmetic functions
    above.  Catches over-large allocations before they get
    to calloc().  Prevents spurious gcc warnings about
    very large allocations, and allows the optimiser
    to convert the overflow cases to an early exit.

  - hts_calloc_ps(size_t sz, size_t a, size_t b)
    Replaces calloc(a + b, sz)

  - hts_calloc_pse(size_t sz, size_t a, size_t b, size_t extra)
    Replaces calloc(sz * (a + b) + extra, 1)

* Wrappers around realloc()

  - hts_realloc(void *orig, size_t size)
    For use with the saturating arithmetic functions
    above.  Catches over-large allocations before they get
    to realloc().  Prevents spurious gcc warnings about
    very large allocations, and allows the optimiser
    to convert the overflow cases to an early exit.

  - hts_realloc_p(void *orig, size_t a, size_t b)
    Replaces realloc(orig, a * b)

  - hts_realloc_ps(void *orig, size_t sz, size_t a, size_t b)
    Replaces realloc(orig, sz * (a + b))

  - hts_realloc_pse(void *orig, size_t sz, size_t a, size_t b,
                    size_t extra)
    Replaces realloc(orig, sz * (a + b) + extra)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant