What is unchecked
imp_apply_field in src/columnar_arrow.c inspects exactly three Arrow type tags — Date,
Time and Timestamp — with default: break for everything else. So on import the file's
declared
Int.bitWidth and Int.is_signed
- floating-point width
FixedSizeBinary.byteWidth
Decimal precision and scale
are never read. The stride and interpretation come from the target PostgreSQL column rather
than from the file. This is the same class of defect as #864/#865, which #870 fixed for the
temporal types only.
What is already safe, so this is not a memory-safety report
The import validates buffer lengths: "value buffer too small for the row count". Any case
where the file's carrier is narrower than the target — float16 into float8,
fixed_size_binary(8) into uuid, int32 into bigint — is refused as corrupt rather than
read out of bounds.
What survives that check, and is therefore silent
Cases where the carrier matches or exceeds the target:
| file declares |
column |
what should happen |
uint64 |
bigint |
values >= 2^63 are read as negative |
int64 |
int / smallint |
stride is the target's, so values are read from the wrong offsets |
decimal128(10,2) |
numeric(20,4) |
same 16-byte carrier, wrong scale — values off by powers of ten |
Status of this report
Read from the code, not measured. I have verified the three-tag limit and the buffer-length
check by reading main; the three outcomes above follow from them but I have not run any of
them. Whoever picks this up should start by building the corpus files and making each one fail
before writing a fix — test/arrow_corpus.py already emits typed Arrow fixtures via pyarrow and
is the natural place to add them.
Prior art
#861 was written to cover exactly this, alongside a temporal policy that has since been decided
the other way (see the closing comment there, and #880). Its non-temporal arms are worth reading
before starting, but not rebasing: that branch predates #870 and its head had deleted its own
Int.is_signed check, so its uint64 into bigint arm was red on its own terms.
What is unchecked
imp_apply_fieldinsrc/columnar_arrow.cinspects exactly three Arrow type tags —Date,TimeandTimestamp— withdefault: breakfor everything else. So on import the file'sdeclared
Int.bitWidthandInt.is_signedFixedSizeBinary.byteWidthDecimalprecision and scaleare never read. The stride and interpretation come from the target PostgreSQL column rather
than from the file. This is the same class of defect as #864/#865, which #870 fixed for the
temporal types only.
What is already safe, so this is not a memory-safety report
The import validates buffer lengths:
"value buffer too small for the row count". Any casewhere the file's carrier is narrower than the target —
float16intofloat8,fixed_size_binary(8)intouuid,int32intobigint— is refused as corrupt rather thanread out of bounds.
What survives that check, and is therefore silent
Cases where the carrier matches or exceeds the target:
uint64bigintint64int/smallintdecimal128(10,2)numeric(20,4)Status of this report
Read from the code, not measured. I have verified the three-tag limit and the buffer-length
check by reading
main; the three outcomes above follow from them but I have not run any ofthem. Whoever picks this up should start by building the corpus files and making each one fail
before writing a fix —
test/arrow_corpus.pyalready emits typed Arrow fixtures via pyarrow andis the natural place to add them.
Prior art
#861 was written to cover exactly this, alongside a temporal policy that has since been decided
the other way (see the closing comment there, and #880). Its non-temporal arms are worth reading
before starting, but not rebasing: that branch predates #870 and its head had deleted its own
Int.is_signedcheck, so itsuint64 into bigintarm was red on its own terms.