Skip to content

Merge upstream#3

Open
rix133 wants to merge 42 commits intorix133:masterfrom
ropensci:master
Open

Merge upstream#3
rix133 wants to merge 42 commits intorix133:masterfrom
ropensci:master

Conversation

@rix133
Copy link
Copy Markdown
Owner

@rix133 rix133 commented Mar 23, 2026

No description provided.

billdenney and others added 12 commits November 25, 2025 10:23
Update to libxlsxwriter version 1.2.3
Protect function definition (noted on rchk result)
* Fix strcpy buffer overflow in C_set_tempdir

C_set_tempdir used strcpy into a fixed 2048-byte buffer with no bounds
check. A path >= 2048 bytes would overflow the buffer. Now validates
the length and raises an informative R error before copying, with
strncpy as a defense-in-depth fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Validate column count against xlsx limit and use lxw_col_t

The data frame column count was stored in size_t and passed to
libxlsxwriter APIs expecting lxw_col_t (uint16_t), causing silent
narrowing. Now validates upfront against LXW_COL_MAX (16384) with an
informative error, and types cols and all column loop indices as
lxw_col_t throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Validate row count against xlsx limit and use lxw_row_t

The row count and cursor were stored in size_t and passed to
libxlsxwriter APIs expecting lxw_row_t (uint32_t), causing silent
narrowing. Now validates the total row count upfront against
LXW_ROW_MAX (1048576), accounting for the optional header row, and
types rows, cursor, and the row loop index as lxw_row_t throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix remaining Rf_length signed/unsigned comparisons

Rf_length() returns R_xlen_t (signed ptrdiff_t). Comparing it against
size_t or lxw_row_t (unsigned) without casting produces signed/unsigned
mismatch warnings and could misbehave if lengths were negative. Fixes:
- Sheet loop: capture Rf_length(df_list) into R_xlen_t nsheets; change
  loop variable s from size_t to R_xlen_t so comparison is signed/signed.
- Per-cell skip guard: cast lxw_row_t i to R_xlen_t before comparing
  with Rf_length(col).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix test calling convention for C_set_tempdir; add NEWS entries

C_set_tempdir is a NativeSymbolInfo object in the namespace (registered
via @useDynLib), not an R function. The test must call it via
.Call(writexl:::C_set_tempdir, arg) rather than
writexl:::C_set_tempdir(arg), matching the pattern used in .onLoad.

Also adds NEWS entries for the memory-safety changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix strcpy buffer overflow in C_set_tempdir

C_set_tempdir used strcpy into a fixed 2048-byte buffer with no bounds
check. A path >= 2048 bytes would overflow the buffer. Now validates
the length and raises an informative R error before copying, with
strncpy as a defense-in-depth fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Validate column count against xlsx limit and use lxw_col_t

The data frame column count was stored in size_t and passed to
libxlsxwriter APIs expecting lxw_col_t (uint16_t), causing silent
narrowing. Now validates upfront against LXW_COL_MAX (16384) with an
informative error, and types cols and all column loop indices as
lxw_col_t throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Validate row count against xlsx limit and use lxw_row_t

The row count and cursor were stored in size_t and passed to
libxlsxwriter APIs expecting lxw_row_t (uint32_t), causing silent
narrowing. Now validates the total row count upfront against
LXW_ROW_MAX (1048576), accounting for the optional header row, and
types rows, cursor, and the row loop index as lxw_row_t throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix remaining Rf_length signed/unsigned comparisons

Rf_length() returns R_xlen_t (signed ptrdiff_t). Comparing it against
size_t or lxw_row_t (unsigned) without casting produces signed/unsigned
mismatch warnings and could misbehave if lengths were negative. Fixes:
- Sheet loop: capture Rf_length(df_list) into R_xlen_t nsheets; change
  loop variable s from size_t to R_xlen_t so comparison is signed/signed.
- Per-cell skip guard: cast lxw_row_t i to R_xlen_t before comparing
  with Rf_length(col).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix test calling convention for C_set_tempdir; add NEWS entries

C_set_tempdir is a NativeSymbolInfo object in the namespace (registered
via @useDynLib), not an R function. The test must call it via
.Call(writexl:::C_set_tempdir, arg) rather than
writexl:::C_set_tempdir(arg), matching the pattern used in .onLoad.

Also adds NEWS entries for the memory-safety changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Refactor: extract per-type cell-writing static functions (no functional change)

Replace the monolithic switch statement in C_write_data_frame_list() with
individual static functions (write_cell_date, write_cell_posixct,
write_cell_string, write_cell_formula, write_cell_hyperlink, write_cell_real,
write_cell_integer, write_cell_logical) dispatched via a new write_cell()
gateway. Introduce a cell_write_ctx struct to carry shared worksheet and
format pointers, with a reserved workbook field for future xl_cell_general
support. No change in behaviour: all existing tests continue to pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: replace GNU-specific pattern rule with portable static library build

Replace the `%.a:` GNU pattern rule in src/Makevars with an explicit
POSIX-portable recipe using `rm -f`, `$(AR) -cr`, and `$(RANLIB)`,
following R's Writing Portable Packages guidance. Remove "GNU make"
from SystemRequirements in DESCRIPTION since it is no longer needed.

Closes #97
* update: libxlsxwriter 1.2.4 with upstream directory structure

Restructure vendored libxlsxwriter source to mirror the upstream
distribution layout under src/libxlsxwriter/:
  src/libxlsxwriter/src/         (was src/libxlsxwriter/)
  src/libxlsxwriter/include/     (was src/include/)
  src/libxlsxwriter/third_party/ (was src/md5/, src/minizip/, src/tmpfileplus/)

This makes future updates a simple copy of the src/, include/, and
third_party/ directories from the upstream tarball. Update src/Makevars
with the new paths and add src/libxlsxwriter/**/Makefile* to .gitignore
so upstream Makefiles are not tracked (they trigger R CMD check warnings
about GNU extensions and are not used by the R build).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: remove unused dtoa third-party directory and gitignore it

dtoa is included in the upstream libxlsxwriter distribution but is not
compiled by the R package — only its header (emyg_dtoa.h) is vendored
via src/libxlsxwriter/include/xlsxwriter/third_party/. Remove the
source directory and add it to .gitignore so it stays absent after
future upstream copy-in updates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: replace inst/COPYRIGHT with symlink to vendored libxlsxwriter License.txt

Vendor src/libxlsxwriter/License.txt from the upstream tarball (more
complete and up-to-date than the old inst/COPYRIGHT) and replace
inst/COPYRIGHT with a git symlink pointing to it. This way future
libxlsxwriter updates automatically keep the license current. Also
note inst/COPYRIGHT in LICENSE for discoverability.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…stub (#104)

minizip cleanup:
- Remove all minizip sources not used by writexl: crypt.h, iowin32.[ch],
  make_vms.com, miniunz.c, minizip.[c1], miniunzip.1, MiniZip64_*.txt,
  README.txt, configure.ac, minizip.pc.in, mztools.[ch], unzip.[ch]
- Keep only ioapi.c, ioapi.h, zip.c, zip.h (the four files compiled by
  src/Makevars)
- Add minizip whitelist rules to root .gitignore so updating from upstream
  cannot accidentally re-add the unused files

Copyright / LICENSE:
- Add Copyright: field to DESCRIPTION referencing the installed COPYRIGHT
  file for bundled third-party notices (libxlsxwriter and dependencies)
- Trim LICENSE stub to the required YEAR + COPYRIGHT HOLDER fields only;
  the third-party note now lives in the DESCRIPTION Copyright field

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

4 participants