es-ude / es-ude/OnDeviceTraining

tensor: N=0 element allocation has implementation-defined behavior

Open
#160 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
1
Forks
3
Avg merge
1d 1h
Merged PRs (30d)
8

Description

**Discovered while drafting BOOL tensor dtype design (2026-05-08).**

`calcNumberOfBytesForData(q, 0)` returns 0 for every dtype (FLOAT32, SYM_INT32, ASYM, and the upcoming BOOL). `initTensor` then calls `reserveMemory(0)` → `calloc(0, 1)`. Per C99 §7.20.3, the behavior is implementation-defined: may return NULL or a unique non-NULL pointer.

## Why it matters

- newlib (common MCU libc) commonly returns NULL for `calloc(0, 1)`; glibc returns a unique non-NULL pointer.
- Consumers that dereference `tensor->data` after constructing a tensor with a zero dimension would crash on newlib but not on glibc.
- `freeTensor` happens to be safe (`free(NULL)` is defined), but consumer code paths may not check first.

## Repro sketch

```c
size_t dims[] = {0, 3};
shape_t shape = { .numberOfDimensions = 2, .dimensions = dims, /* ... */ };
quantization_t q;
initFloat32Quantization(&q);
tensor_t *t = initTensor(&shape, &q, NULL);
// t->data may be NULL (newlib) or non-NULL (glibc) — undefined-by-spec
```

## Suggested fix (decision needed)

- (a) `initTensor` sets `t->data = NULL` for N=0, document, add consumer guards.
- (b) `reserveMemory` always returns a non-NULL sentinel pointer for size 0.
- (c) `initTensor` rejects N=0 with `PRINT_ERROR` (likely too aggressive).

Whichever is chosen, cover with a regression test on the arm-gcc/newlib toolchain that exhibits the NULL behavior.

## Scope

Pre-existing latent hazard, not specific to any dtype. No current crash. Filed during BOOL dtype design so it's tracked, not lost.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.