Skip to content

Commit d2c0c06

Browse files
authored
Merge branch 'master' into eval-copy-less
2 parents 18ec3d1 + 3f876bc commit d2c0c06

File tree

3 files changed

+75
-45
lines changed

3 files changed

+75
-45
lines changed

src/libexpr/include/nix/expr/eval.hh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,15 @@ private:
508508

509509
public:
510510

511+
/**
512+
* @param lookupPath Only used during construction.
513+
* @param store The store to use for instantiation
514+
* @param fetchSettings Must outlive the lifetime of this EvalState!
515+
* @param settings Must outlive the lifetime of this EvalState!
516+
* @param buildStore The store to use for builds ("import from derivation", C API `nix_string_realise`)
517+
*/
511518
EvalState(
512-
const LookupPath & _lookupPath,
519+
const LookupPath & lookupPath,
513520
ref<Store> store,
514521
const fetchers::Settings & fetchSettings,
515522
const EvalSettings & settings,

src/libstore/aws-creds.cc

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -118,48 +118,57 @@ AwsCredentials getAwsCredentials(const std::string & profile)
118118
// Get or create credential provider with caching
119119
std::shared_ptr<Aws::Crt::Auth::ICredentialsProvider> provider;
120120

121-
// Try to find existing provider
122-
credentialProviderCache.visit(profile, [&](const auto & pair) { provider = pair.second; });
123-
124-
if (!provider) {
125-
// Create new provider if not found
126-
debug(
127-
"[pid=%d] creating new AWS credential provider for profile '%s'",
128-
getpid(),
129-
profile.empty() ? "(default)" : profile.c_str());
130-
131-
try {
132-
initAwsCrt();
133-
134-
if (profile.empty()) {
135-
Aws::Crt::Auth::CredentialsProviderChainDefaultConfig config;
136-
config.Bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap();
137-
provider = Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderChainDefault(config);
138-
} else {
139-
Aws::Crt::Auth::CredentialsProviderProfileConfig config;
140-
config.Bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap();
141-
// This is safe because the underlying C library will copy this string
142-
// c.f. https://github.com/awslabs/aws-c-auth/blob/main/source/credentials_provider_profile.c#L220
143-
config.ProfileNameOverride = Aws::Crt::ByteCursorFromCString(profile.c_str());
144-
provider = Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderProfile(config);
145-
}
146-
} catch (Error & e) {
147-
e.addTrace(
148-
{},
149-
"while creating AWS credentials provider for %s",
150-
profile.empty() ? "default profile" : fmt("profile '%s'", profile));
151-
throw;
152-
}
153-
154-
if (!provider) {
155-
throw AwsAuthError(
156-
"Failed to create AWS credentials provider for %s",
157-
profile.empty() ? "default profile" : fmt("profile '%s'", profile));
158-
}
121+
// Use try_emplace_and_cvisit for atomic get-or-create
122+
// This prevents race conditions where multiple threads create providers
123+
credentialProviderCache.try_emplace_and_cvisit(
124+
profile,
125+
nullptr, // Placeholder - will be replaced in f1 before any thread can see it
126+
[&](auto & kv) {
127+
// f1: Called atomically during insertion with non-const reference
128+
// Other threads are blocked until we finish, so nullptr is never visible
129+
debug(
130+
"[pid=%d] creating new AWS credential provider for profile '%s'",
131+
getpid(),
132+
profile.empty() ? "(default)" : profile.c_str());
159133

160-
// Insert into cache (try_emplace is thread-safe and won't overwrite if another thread added it)
161-
credentialProviderCache.try_emplace(profile, provider);
162-
}
134+
try {
135+
initAwsCrt();
136+
137+
if (profile.empty()) {
138+
Aws::Crt::Auth::CredentialsProviderChainDefaultConfig config;
139+
config.Bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap();
140+
kv.second = Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderChainDefault(config);
141+
} else {
142+
Aws::Crt::Auth::CredentialsProviderProfileConfig config;
143+
config.Bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap();
144+
// This is safe because the underlying C library will copy this string
145+
// c.f. https://github.com/awslabs/aws-c-auth/blob/main/source/credentials_provider_profile.c#L220
146+
config.ProfileNameOverride = Aws::Crt::ByteCursorFromCString(profile.c_str());
147+
kv.second = Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderProfile(config);
148+
}
149+
150+
if (!kv.second) {
151+
throw AwsAuthError(
152+
"Failed to create AWS credentials provider for %s",
153+
profile.empty() ? "default profile" : fmt("profile '%s'", profile));
154+
}
155+
156+
provider = kv.second;
157+
} catch (Error & e) {
158+
// Exception during creation - remove the entry to allow retry
159+
credentialProviderCache.erase(profile);
160+
e.addTrace({}, "for AWS profile: %s", profile.empty() ? "(default)" : profile);
161+
throw;
162+
} catch (...) {
163+
// Non-Error exception - still need to clean up
164+
credentialProviderCache.erase(profile);
165+
throw;
166+
}
167+
},
168+
[&](const auto & kv) {
169+
// f2: Called if key already exists (const reference)
170+
provider = kv.second;
171+
});
163172

164173
return getCredentialsFromProvider(provider);
165174
}

src/libutil/include/nix/util/error.hh

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,27 @@ public:
192192
err.traces.push_front(trace);
193193
}
194194

195+
/**
196+
* Prepends an item to the error trace, as is usual for extra context.
197+
*
198+
* @param pos Nullable source position to put in trace item
199+
* @param fs Format string, see `HintFmt`
200+
* @param args... Format string arguments.
201+
*/
195202
template<typename... Args>
196-
void addTrace(std::shared_ptr<const Pos> && e, std::string_view fs, const Args &... args)
203+
void addTrace(std::shared_ptr<const Pos> && pos, std::string_view fs, const Args &... args)
197204
{
198-
addTrace(std::move(e), HintFmt(std::string(fs), args...));
205+
addTrace(std::move(pos), HintFmt(std::string(fs), args...));
199206
}
200207

201-
void addTrace(std::shared_ptr<const Pos> && e, HintFmt hint, TracePrint print = TracePrint::Default);
208+
/**
209+
* Prepends an item to the error trace, as is usual for extra context.
210+
*
211+
* @param pos Nullable source position to put in trace item
212+
* @param hint Formatted error message
213+
* @param print Optional, whether to always print (used by `addErrorContext`)
214+
*/
215+
void addTrace(std::shared_ptr<const Pos> && pos, HintFmt hint, TracePrint print = TracePrint::Default);
202216

203217
bool hasTrace() const
204218
{

0 commit comments

Comments
 (0)