Handle foreign-owned compile artifacts

This commit is contained in:
udo
2026-07-19 05:20:08 +00:00
parent 4f010d37a0
commit ccbe945d62
7 changed files with 201 additions and 15 deletions
+127 -8
View File
@@ -386,6 +386,97 @@ static bool compiler_publish_staged_artifacts(SharedUnit* su, String staged_pre_
file_unlink(it->previous);
}
};
auto copy_previous = [&](const Artifact& artifact, int link_error) {
struct stat path_info;
if(lstat(artifact.canonical.c_str(), &path_info) != 0 || !S_ISREG(path_info.st_mode))
{
error = "refusing non-regular bounded compile artifact " + artifact.canonical;
return(false);
}
int input = open(artifact.canonical.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
if(input < 0)
{
error = "could not read previous bounded compile artifact " + artifact.canonical +
" after hard-link failure " + String(std::strerror(link_error)) + ": " + std::strerror(errno);
return(false);
}
struct stat source_info;
if(fstat(input, &source_info) != 0)
{
error = "could not inspect previous bounded compile artifact " + artifact.canonical + ": " + std::strerror(errno);
close(input);
return(false);
}
if(source_info.st_dev != path_info.st_dev || source_info.st_ino != path_info.st_ino || !S_ISREG(source_info.st_mode))
{
error = "bounded compile artifact changed while preserving " + artifact.canonical;
close(input);
return(false);
}
int output = open(artifact.previous.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, source_info.st_mode & 07777);
if(output < 0)
{
error = "could not create bounded compile rollback copy " + artifact.previous + ": " + std::strerror(errno);
close(input);
return(false);
}
bool copied = true;
char buffer[65536];
while(copied)
{
if(deadline && deadline->expire_if_needed())
{
error = "bounded compile deadline expired while copying previous artifact " + artifact.canonical;
copied = false;
break;
}
ssize_t got = read(input, buffer, sizeof(buffer));
if(got == 0)
break;
if(got < 0)
{
if(errno == EINTR)
continue;
error = "could not read previous bounded compile artifact " + artifact.canonical + ": " + std::strerror(errno);
copied = false;
break;
}
ssize_t written = 0;
while(written < got)
{
if(deadline && deadline->expire_if_needed())
{
error = "bounded compile deadline expired while copying previous artifact " + artifact.canonical;
copied = false;
break;
}
ssize_t amount = write(output, buffer + written, got - written);
if(amount < 0 && errno == EINTR)
continue;
if(amount <= 0)
{
error = "could not copy previous bounded compile artifact " + artifact.canonical + ": " + std::strerror(errno);
copied = false;
break;
}
written += amount;
}
}
if(copied && fchmod(output, source_info.st_mode & 07777) != 0)
{
error = "could not preserve mode for bounded compile artifact " + artifact.canonical + ": " + std::strerror(errno);
copied = false;
}
if(close(output) != 0 && copied)
{
error = "could not close bounded compile rollback copy " + artifact.previous + ": " + std::strerror(errno);
copied = false;
}
close(input);
if(!copied)
file_unlink(artifact.previous);
return(copied);
};
for(auto& artifact : artifacts)
{
if(deadline && deadline->expire_if_needed())
@@ -399,10 +490,20 @@ static bool compiler_publish_staged_artifacts(SharedUnit* su, String staged_pre_
artifact.existed = file_exists(artifact.canonical);
if(artifact.existed && link(artifact.canonical.c_str(), artifact.previous.c_str()) != 0)
{
error = "could not preserve previous bounded compile artifacts: " + String(std::strerror(errno));
for(auto& cleanup : artifacts)
file_unlink(cleanup.previous);
return(false);
int link_error = errno;
if(link_error != EPERM && link_error != EACCES && link_error != EMLINK && link_error != EXDEV)
{
error = "could not preserve previous bounded compile artifact " + artifact.canonical + ": " + std::strerror(link_error);
for(auto& cleanup : artifacts)
file_unlink(cleanup.previous);
return(false);
}
if(!copy_previous(artifact, link_error))
{
for(auto& cleanup : artifacts)
file_unlink(cleanup.previous);
return(false);
}
}
}
for(auto& artifact : artifacts)
@@ -417,7 +518,7 @@ static bool compiler_publish_staged_artifacts(SharedUnit* su, String staged_pre_
file_unlink(artifact.canonical);
else if(rename(artifact.staged.c_str(), artifact.canonical.c_str()) != 0)
{
error = "could not publish bounded compile artifacts: " + String(std::strerror(errno));
error = "could not publish bounded compile artifact " + artifact.canonical + ": " + std::strerror(errno);
rollback();
return(false);
}
@@ -547,6 +648,8 @@ int compiler_open_lock_file(String file_name, String purpose, bool nonblocking =
if(lock_dir != "")
mkdir(lock_dir);
int fdlock = open(file_name.c_str(), O_RDWR | O_CREAT, 0666);
if(fdlock == -1 && (errno == EACCES || errno == EPERM))
fdlock = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
if(fdlock == -1)
{
printf("(!) Could not open lock file %s\n", file_name.c_str());
@@ -575,6 +678,8 @@ int compiler_open_lock_file_bounded(String file_name, String purpose, CompilerDe
if(lock_dir != "")
mkdir(lock_dir);
int fdlock = open(file_name.c_str(), O_RDWR | O_CREAT, 0666);
if(fdlock == -1 && (errno == EACCES || errno == EPERM))
fdlock = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
if(fdlock == -1)
return(-1);
fcntl(fdlock, F_SETFD, FD_CLOEXEC);
@@ -604,6 +709,16 @@ void compiler_close_lock_file(int fdlock)
close(fdlock);
}
static void compiler_publish_source_generation(String file_name)
{
String staged_file_name = file_name + ".stage-" + std::to_string((u64)getpid());
file_unlink(staged_file_name);
if(file_put_contents(staged_file_name, std::to_string(getpid()) + ":" + std::to_string((u64)(time_precise() * 1000000.0)) + "\n") &&
rename(staged_file_name.c_str(), file_name.c_str()) != 0)
printf("(!) Could not publish %s: %s\n", file_name.c_str(), std::strerror(errno));
file_unlink(staged_file_name);
}
static void compiler_mark_source_generation_nonblocking(Request* context)
{
if(!context || !context->server)
@@ -612,7 +727,7 @@ static void compiler_mark_source_generation_nonblocking(Request* context)
int fdlock = compiler_open_lock_file(file_name + ".lock", "source-generation", true);
if(fdlock < 0)
return;
file_put_contents(file_name, std::to_string(getpid()) + ":" + std::to_string((u64)(time_precise() * 1000000.0)) + "\n");
compiler_publish_source_generation(file_name);
compiler_close_lock_file(fdlock);
}
@@ -1520,7 +1635,7 @@ void compiler_mark_source_generation(Request* context)
int fdlock = compiler_open_lock_file(file_name + ".lock", "source-generation");
if(fdlock < 0)
return;
file_put_contents(file_name, std::to_string(getpid()) + ":" + std::to_string((u64)(time_precise() * 1000000.0)) + "\n");
compiler_publish_source_generation(file_name);
compiler_close_lock_file(fdlock);
}
@@ -1983,10 +2098,12 @@ bool unit_compile(String path)
return(su && trim(su->compiler_messages) == "" && file_exists(su->wasm_name));
}
bool unit_compile_bounded(Request* request, String path, u64 timeout_ms, bool* timed_out)
bool unit_compile_bounded(Request* request, String path, u64 timeout_ms, bool* timed_out, String* error)
{
if(timed_out)
*timed_out = false;
if(error)
error->clear();
if(!request || timeout_ms == 0)
{
if(timed_out)
@@ -2006,5 +2123,7 @@ bool unit_compile_bounded(Request* request, String path, u64 timeout_ms, bool* t
auto su = compiler_get_shared_unit_internal(request, resolved_path, true, false, &deadline);
if(timed_out)
*timed_out = deadline.timed_out;
if(error)
*error = first(deadline.operational_error, su ? trim(su->compiler_messages) : "");
return(su && trim(su->compiler_messages) == "" && file_exists(su->wasm_name));
}
+1 -1
View File
@@ -28,7 +28,7 @@ SharedUnit* get_shared_unit(Request* context, String file_name);
#ifndef __UCE_WASM_UNIT__
SharedUnit* get_shared_unit_for_preprocess(Request* context, String file_name);
SharedUnit* get_shared_unit_bounded(Request* context, String file_name, u64 timeout_ms, bool* timed_out);
bool unit_compile_bounded(Request* context, String path, u64 timeout_ms, bool* timed_out);
bool unit_compile_bounded(Request* context, String path, u64 timeout_ms, bool* timed_out, String* error = 0);
#endif
String compiler_error_page_unit(Request* context, String config_key);
bool compiler_unit_compile_pending(Request* context, String file_name);
+7 -1
View File
@@ -3801,9 +3801,15 @@ private:
{
u64 remaining_ms = self->invocation_remaining_ms();
bool timed_out = false;
bool ok = remaining_ms > 0 && unit_compile_bounded(context, request["path"].to_string(), remaining_ms, &timed_out);
String compile_error;
bool ok = remaining_ms > 0 && unit_compile_bounded(context, request["path"].to_string(), remaining_ms, &timed_out, &compile_error);
if(timed_out || remaining_ms == 0)
return(Trap(self->invocation_timeout_error()));
if(!ok && compile_error != "")
{
response["error"] = compile_error;
printf("(!) unit_compile failed for %s: %s\n", request["path"].to_string().c_str(), compile_error.c_str());
}
response["ok"].set_bool(ok);
}
else if(op == "call")