Skip to content

lib/gis: set buffer to G_format_[northing|easting|resolution] to >=320 bytes - #7943

Merged
nilason merged 1 commit into
OSGeo:mainfrom
Pranav-error:fix-format-double-overflow
Sep 29, 2026
Merged

nilason merged 1 commit into
OSGeo:mainfrom
Pranav-error:fix-format-double-overflow

Conversation

@Pranav-error

Copy link
Copy Markdown
Contributor

Fixes #7942.

format_double() (lib/gis/wind_format.c) uses sprintf(buf, "%.8f", value) for any non-lat/lon projection. %.8f on a double has no fixed maximum width -- DBL_MAX needs 318 characters -- but the callers changed here pass a fixed local buffer sized for an ordinary coordinate: 30 bytes in r.coin, 50 in r.report, ps.map, and d.where.

The value comes from the current region, settable via g.region. scan_double() (lib/gis/wind_scan.c), which parses g.region's n=/s=/e=/w= for any non-lat/lon projection, is a bare sscanf with no magnitude check, so an extreme value is accepted and can reach these buffers when one of the four programs formats it.

Reproduced with format_double() extracted verbatim (matched by function name, not retyped) into a standalone harness under AddressSanitizer: 9e19 (29-char result) is clean, 1e20 (30 characters, one more than a 30-byte buffer can hold with the terminator) overflows. DBL_MAX needs exactly 318 characters, measured directly with sprintf into a 512-byte scratch buffer.

Fix: bump each buffer to 320 bytes (sign + DBL_MAX's 318 digits + terminator) rather than changing format_double()'s signature -- it's called from many places across the tree with no size parameter today, and widening a public API felt like a separate decision from fixing four buffers that are simply too small for what it already does. Happy to go the other way (a bounded snprintf inside format_double() itself) if you'd rather standardize there.

Testing: clang-format is clean on all four files. I did not attempt a full build -- this machine is low on disk space, and the change is a pure buffer-size literal with no logic difference (same four lines, larger numbers), so a full multi-GB build felt like more risk to my disk than confidence gained. The actual defect (the unbounded write) is what's ASAN-verified above; each affected call site was individually located and its buffer size checked, not assumed from the one function.

Copilot AI lite review requested due to automatic review settings September 23, 2026 17:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@nilason

nilason commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Please remove the comments, the info belongs to the commit message.

@echoix

echoix commented Sep 23, 2026

Copy link
Copy Markdown
Member

How were you able to do the asan verifications before and after (if you actually did), without doing a grass build? Seems a little contradictory, unless not explained well

@github-actions github-actions Bot added raster Related to raster data processing C Related code is in C module display labels Sep 23, 2026
@Pranav-error

Copy link
Copy Markdown
Contributor Author

Yes -- no full build, deliberately. format_double() (and the four call sites) were extracted verbatim, matched by function name and not retyped, into a standalone harness compiled with -fsanitize=address. The harness calls the function directly with the boundary values (9e19, 1e20, DBL_MAX) against a buffer sized like the real one, so ASAN can catch the overflow at the exact byte. Disk space on this machine ruled out a full GRASS build (same constraint as the buffer sizes themselves being small local arrays -- no logic change, just literals), so that's the extent of the verification: the extracted function under ASAN, not the built binary in the full pipeline.

Happy to do a full build and rerun if that's wanted for confidence here -- just flagging it wasn't done yet.

@nilason

nilason commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

This looks good to me, but, again please remove the comments in code. You might add a very short notice (on min buffer size) in the functions \param dox in lib/gis/wind_format.c.

@Pranav-error
Pranav-error force-pushed the fix-format-double-overflow branch 2 times, most recently from bb61c21 to 6b39ba5 Compare September 25, 2026 12:26
@Pranav-error

Copy link
Copy Markdown
Contributor Author

Added a short note on the minimum buffer size to the \param[out] buf docs for G_format_northing/G_format_easting/G_format_resolution in wind_format.c. Comments removed from all four call sites.

Comment thread lib/gis/wind_format.c Resolved
format_double() (lib/gis/wind_format.c) formats a coordinate with
sprintf(buf, "%.8f", value) for any non-lat/lon projection. %.8f on a
double has no fixed maximum width -- DBL_MAX needs 318 characters --
but several callers pass a fixed local buffer sized for an ordinary
coordinate: 30 bytes in r.coin, 50 in r.report, ps.map, and d.where.

g.region's coordinate parser (scan_double() in wind_scan.c) is a bare
sscanf with no magnitude check, so an extreme n=/s=/e=/w= value in a
non-lat/lon projection is accepted, and the region's stored coordinate
can be large enough to overflow these buffers when one of the four
affected programs formats it.

Reproduced with format_double() extracted verbatim into a standalone
harness under AddressSanitizer: 9e19 (29-char result) is clean, 1e20
(30 characters, one more than a 30-byte buffer can hold with the
terminator) overflows. DBL_MAX needs exactly 318 characters, measured
directly.

Bumped each of the four buffers to 320 bytes -- sign + DBL_MAX's 318
digits + the terminator -- rather than changing format_double()'s
signature, which is called from many places across the tree with no
size parameter today and felt like a separate, bigger decision. Fixes
OSGeo#7942.

Could not build the full tree to test end to end -- this machine is
already tight on disk space, and the change is a pure buffer-size
literal with no logic difference, so I didn't think it was worth the
risk for the confidence gained. clang-format is clean on all four
files.

Signed-off-by: sai pranav <rajasaipranav0@gmail.com>
@Pranav-error
Pranav-error force-pushed the fix-format-double-overflow branch from 6b39ba5 to a078add Compare September 29, 2026 07:21
@Pranav-error

Copy link
Copy Markdown
Contributor Author

Taken exactly as suggested, applied to all three functions (G_format_northing/easting/resolution).

@nilason nilason changed the title Bound the buffers G_format_northing/easting/resolution write into lib/gis: set buffer to G_format_[northing|easting|resolution] to >=320 bytes Sep 29, 2026
@nilason
nilason merged commit 373ece5 into OSGeo:main Sep 29, 2026
26 of 30 checks passed
@github-actions github-actions Bot added this to the 8.6.0 milestone Sep 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C Related code is in C display libraries module raster Related to raster data processing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

format_double()'s unbounded %.8f overflows several fixed-size caller buffers

4 participants