```python
"""A block-allocation bitmap: 32-bit words, LSB-first, a set bit is occupied."""

WORD_BITS = 32
WORD_MAX = 0xFFFFFFFF


def _whole(value):
    return not isinstance(value, bool) and isinstance(value, int)


def _check_words(words):
    for word in words:
        if not _whole(word) or word < 0 or word > WORD_MAX:
            raise ValueError("bitmap words must be integers from 0 to 4294967295")


def _bit_of(words, index):
    return (words[index // WORD_BITS] >> (index % WORD_BITS)) & 1


def bit_at(words, index):
    _check_words(words)
    if not _whole(index):
        raise ValueError("bit index must be an integer")
    if index < 0 or index >= len(words) * WORD_BITS:
        raise ValueError("bit index is outside the words")
    return _bit_of(words, index)


def occupy_run(words, start, length):
    _check_words(words)
    if not _whole(start) or start < 0:
        raise ValueError("run start must be a non-negative integer")
    if not _whole(length) or length <= 0:
        raise ValueError("run length must be a positive integer")
    if start + length > len(words) * WORD_BITS:
        raise ValueError("run leaves the words")
    for i in range(start, start + length):
        if _bit_of(words, i) == 1:
            raise ValueError("run touches an occupied block")
    marked = list(words)
    for i in range(start, start + length):
        marked[i // WORD_BITS] |= 1 << (i % WORD_BITS)
    return marked


def find_free_run(words, capacity, length):
    _check_words(words)
    if not _whole(capacity) or capacity <= 0:
        raise ValueError("capacity must be a positive integer")
    if len(words) * WORD_BITS != capacity:
        raise ValueError("word count disagrees with the capacity")
    if not _whole(length) or length <= 0:
        raise ValueError("run length must be a positive integer")

    # Calculate the number of words needed for the capacity
    num_words = (capacity + WORD_BITS - 1) // WORD_BITS

    # Check if the words list has enough words
    if len(words) != num_words:
        raise ValueError("word count disagrees with the capacity")

    # Initialize the free run start index
    free_start = 0

    # Iterate over each word
    for word_index in range(num_words):
        word = words[word_index]

        # Check if the word is all zeros
        if word == 0:
            # If it's the first word, check if it's within the capacity
            if word_index == 0:
                if length > capacity:
                    return -1
                free_start = word_index * WORD_BITS
            else:
                # If it's not the first word, check if it's within the capacity
                if length > (num_words - word_index) * WORD_BITS:
                    return -1
                free_start += word_index * WORD_BITS

        # If the word is not all zeros, check for a free run
        else:
            # Find the first set bit
            for bit_index in range(WORD_BITS):
                if (word >> bit_index) & 1 == 1:
                    break
            else:
                # If no set bit is found, the word is all zeros
                continue

            # Check if the run starts within the capacity
            if bit_index >= length:
                return free_start

