Skip to content

Fix UB: Remove flexible array member from Operation class#1486

Closed
taoting1234 wants to merge 2 commits into
alibaba:mainfrom
taoting1234:fix/remove-flexible-array-member-ub
Closed

Fix UB: Remove flexible array member from Operation class#1486
taoting1234 wants to merge 2 commits into
alibaba:mainfrom
taoting1234:fix/remove-flexible-array-member-ub

Conversation

@taoting1234

Copy link
Copy Markdown
Contributor

Replace char _buf[0] (flexible array member, UB in C++) with explicit buffer pointer management to avoid undefined behavior.

Problem with Clang

When compiled with Clang under -O2 optimization, the flexible array member causes the compiler to optimize away the default constructor of Operation. This leads to uninitialized members (e.g., StoredURL proxy_url), causing SEGV crashes when the destructor attempts to free uninitialized pointers.

Example crash:
==ERROR: AddressSanitizer: SEGV on unknown address
#0 URL::~URL() at url.h:58:9
#1 StoredURL::~StoredURL() at url.h:113:5
#2 Operation::~Operation() at client.h:142:30

The issue occurs because:

  1. Flexible array member (char _buf[0]) is not standard C++
  2. Clang treats the class as having trivial initialization
  3. Under -O2, the constructor call is optimized away
  4. Stack-allocated OperationOnStack objects have uninitialized members

Changes

  • Replace char _buf[0] with char* _buf pointing to external buffer
  • Add internal constructors accepting buffer pointer parameter
  • Heap-allocated Operation (via create()) uses buffer after object (this + 1)
  • Stack-allocated OperationOnStack passes its _buf array to base constructor

This eliminates two sources of UB:

  1. Flexible array member (char _buf[0]) - not standard C++
  2. Derived class overriding base class member (char _buf[BufferSize])

The fix ensures correct behavior regardless of compiler optimizations and eliminates potential issues with -O2 or different compiler versions.

Verified: DadiCacheTest passes with ASAN enabled, no SEGV crashes.

Replace char _buf[0] (flexible array member, UB in C++) with explicit
buffer pointer management to avoid undefined behavior.

## Problem with Clang

When compiled with Clang under -O2 optimization, the flexible array member
causes the compiler to optimize away the default constructor of Operation.
This leads to uninitialized members (e.g., StoredURL proxy_url), causing
SEGV crashes when the destructor attempts to free uninitialized pointers.

Example crash:
  ==ERROR: AddressSanitizer: SEGV on unknown address
  #0 URL::~URL() at url.h:58:9
  #1 StoredURL::~StoredURL() at url.h:113:5
  alibaba#2 Operation::~Operation() at client.h:142:30

The issue occurs because:
1. Flexible array member (char _buf[0]) is not standard C++
2. Clang treats the class as having trivial initialization
3. Under -O2, the constructor call is optimized away
4. Stack-allocated OperationOnStack objects have uninitialized members

## Changes

- Replace char _buf[0] with char* _buf pointing to external buffer
- Add internal constructors accepting buffer pointer parameter
- Heap-allocated Operation (via create()) uses buffer after object (this + 1)
- Stack-allocated OperationOnStack passes its _buf array to base constructor

This eliminates two sources of UB:
1. Flexible array member (char _buf[0]) - not standard C++
2. Derived class overriding base class member (char _buf[BufferSize])

The fix ensures correct behavior regardless of compiler optimizations
and eliminates potential issues with -O2 or different compiler versions.

Verified: DadiCacheTest passes with ASAN enabled, no SEGV crashes.
Add test to verify OperationOnStack correctly initializes all members,
particularly proxy_url. This test catches the UB caused by flexible
array member where Clang -O2 optimizes away the constructor, leaving
proxy_url.m_url uninitialized (garbage pointer), which causes SEGV
when the destructor attempts to free it.

The test:
- Creates OperationOnStack with various buffer sizes
- Verifies proxy_url.empty() returns true (m_url == nullptr)
- Lets objects go out of scope to trigger destructor
- With UB, destructor would SEGV on free(garbage)

Note: This issue only manifests with Clang under -O2 optimization.
GCC and Clang -O0 may not trigger the problematic optimization,
but the test ensures correct behavior across all compilers.
@lihuiba

lihuiba commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

As flexible array is a standard feature of C, it is highly unlikely that a decent compiler breaks it with optimization on.

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.

2 participants