Skip to content

Case 46: Pointer Chain Type Change

Field Value
Verdict ๐Ÿ”ด BREAKING
Category Breaking
Platforms Linux, macOS, Windows
Flags ABI break, API break
Detected ChangeKinds โ€”
Source files browse on GitHub

Category: Breaking | Verdict: ๐Ÿ”ด BREAKING

What breaks

Functions return int** and accept int*const* in v1. In v2, the ultimate pointee type changes from int to long. Callers that dereference the returned pointer chain and write int-sized values will corrupt memory โ€” long is 8 bytes on 64-bit, int is 4 bytes, so every write is half the expected size.

Why abidiff catches it

abidiff reports Function_Return_Type_Change (indirect pointee type) and exits 4. abicheck detects: FUNC_RETURN_CHANGED, PARAM_TYPE_CHANGED.

Code diff

v1.h v2.h
int **get_matrix(void); long **get_matrix(void);
void set_cell(int *const *matrix, int row, int col, int val); void set_cell(long *const *matrix, int row, int col, long val);
int sum_row(int *const *matrix, int row, int cols); long sum_row(long *const *matrix, int row, int cols);

Real Failure Demo

Severity: ๐Ÿ”ด CRITICAL โ€” silent memory corruption

Scenario: v1 caller writes int values into memory allocated for long โ€” adjacent cells are overwritten.

gcc -shared -fPIC -g v1.c -o libv1.so
gcc -shared -fPIC -g v2.c -o libv2.so

abidw --out-file v1.abi libv1.so
abidw --out-file v2.abi libv2.so
abidiff v1.abi v2.abi
echo "exit: $?"   # โ†’ 4 (FUNC_RETURN_CHANGED)

Reproduce manually

gcc -shared -fPIC -g v1.c -o libv1.so
gcc -shared -fPIC -g v2.c -o libv2.so
abidw --headers-dir . --out-file v1.abi libv1.so
abidw --headers-dir . --out-file v2.abi libv2.so
abidiff v1.abi v2.abi

How to fix

  1. Opaque element type: typedef int mat_cell_t; at the API boundary โ€” change only the typedef.
  2. Never change primitive types deep in pointer chains โ€” consumers are forced to cast through every level.
  3. SONAME bump if the type change is unavoidable.

Source files

See also: Examples overview ยท All BREAKING cases ยท Category: Breaking.