Skip to content

Bit Shift Overflow in lfs_frombe32 and lfs_fromle32 on MSP430 (16-bit Architecture) #1087

Open
@selimkeles

Description

@selimkeles

Description

When compiling LittleFS on the MSP430 (a 16-bit architecture), the functions lfs_frombe32() and lfs_fromle32 causes incorrect results due to implicit integer promotion rules and bit shift behavior. Since int is 16-bit on MSP430, shifting beyond 16 bits leads to unintended overflows, resulting in incorrect byte-order conversions.

Affected Function

File: lfs_util.h
// Convert between 32-bit big-endian and native order
static inline uint32_t lfs_frombe32(uint32_t a) {
#if !defined(LFS_NO_INTRINSICS) && ( \
    (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
    (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
    (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
    return __builtin_bswap32(a);
#elif (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
    (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
    (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
    return a;
#else
    return (((uint8_t*)&a)[0] << 24) |     // Incorrect behavior on 16-bit platforms
           (((uint8_t*)&a)[1] << 16) |     // Incorrect behavior on 16-bit platforms
           (((uint8_t*)&a)[2] <<  8) |
           (((uint8_t*)&a)[3] <<  0);  
#endif
}
// Convert between 32-bit little-endian and native order
static inline uint32_t lfs_fromle32(uint32_t a) {
#if (defined(  BYTE_ORDER  ) && defined(  ORDER_LITTLE_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_LITTLE_ENDIAN  ) || \
    (defined(__BYTE_ORDER  ) && defined(__ORDER_LITTLE_ENDIAN  ) && __BYTE_ORDER   == __ORDER_LITTLE_ENDIAN  ) || \
    (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
    return a;
#elif !defined(LFS_NO_INTRINSICS) && ( \
    (defined(  BYTE_ORDER  ) && defined(  ORDER_BIG_ENDIAN  ) &&   BYTE_ORDER   ==   ORDER_BIG_ENDIAN  ) || \
    (defined(__BYTE_ORDER  ) && defined(__ORDER_BIG_ENDIAN  ) && __BYTE_ORDER   == __ORDER_BIG_ENDIAN  ) || \
    (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
    return __builtin_bswap32(a);
#else
    return (((uint8_t*)&a)[0] <<  0) |
           (((uint8_t*)&a)[1] <<  8) |
           (((uint8_t*)&a)[2] << 16) |    // Incorrect behavior on 16-bit platforms
           (((uint8_t*)&a)[3] << 24);    // Incorrect behavior on 16-bit platforms
#endif
}

Issue Details

On MSP430, the bit shifts in the #else case result in an integer overflow due to implicit type promotion. Since int is 16-bit, shifting beyond 16 bits results in data loss or sign extension issues.

Proposed Fix

Explicitly cast each shifted value to uint32_t to ensure correct promotion and prevent overflow:

#else
    return ((uint32_t)((uint8_t*)&a)[0] << 24) |
           ((uint32_t)((uint8_t*)&a)[1] << 16) |
           ((uint32_t)((uint8_t*)&a)[2] <<  8) |
           ((uint32_t)((uint8_t*)&a)[3] <<  0);
#endif
#else
    return ((uint32_t)((uint8_t*)&a)[0] <<  0) |
           ((uint32_t)((uint8_t*)&a)[1] <<  8) |
           ((uint32_t)((uint8_t*)&a)[2] << 16) |
           ((uint32_t)((uint8_t*)&a)[3] << 24);
#endif

Impact

This issue affects all 16-bit architectures where int is not 32-bit.
The incorrect byte-order conversion may lead to corrupted metadata or failed mount operations in LittleFS.

Steps to Reproduce

Compile and run LittleFS on MSP430 or another 16-bit platform.
Observe incorrect behavior in functions relying on lfs_frombe32, such as mounting (lfs_mount).
Apply the proposed fix and verify that the issue no longer occurs.

Request

Please consider merging the proposed fix to ensure compatibility with 16-bit architectures. I am happy to contribute further testing or submit a PR if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs fixwe know what is wrong

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions