lib/proj: fix data race on METERS_in/METERS_out in coordinate transform functions - #7764
Merged
Merged
Conversation
The file-scope variables METERS_in and METERS_out were written on every call to GPJ_transform, GPJ_transform_array, pj_do_proj, and pj_do_transform. When GPJ_transform is called from multiple threads, ThreadSanitizer reports data races on both variables even when each thread uses its own cloned PJ object. Each function writes both variables before reading them, so they carry no state between calls. This change makes them locals of the four functions and removes the file-scope declaration. Output is unchanged.
echoix
approved these changes
Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the small separate PR for the globals fix suggested in the review of #7627.
GPJ_transform and three other functions in do_proj.c share two variables, METERS_in and METERS_out, that live at file scope. Every call writes into them. So if two threads call these functions at the same time, they both write into the same shared variables. This could cause a data race. It doesn't matter that each thread has its own cloned PJ object, because the race is on these shared variables and not on the PJ. In practice the output still came out correct since every thread happened to write the same values, but it is still undefined behavior and thread sanitizer found it.
The fix itself was pretty simple. Each of the four functions now has its own local copy of the two variables instead of sharing one pair at file scope. Each function already sets both values before using them, on every path through the code, so nothing about the output changes.
How I verified it:
I wrote a small test program where 8 threads call GPJ_transform at the same time, each thread with its own cloned PJ. On the old code, thread sanitizer reports data races on METERS_in and METERS_out in both transform directions. With this change, the same test runs clean in both directions. I also built r.proj with the change and its output is bit for bit identical to the unmodified module. I tested this with the nearest and bilinear methods.