fix(compiler): skip auto-Drop after field/let/return moves
Track locals moved by value into struct fields, let bindings, or return
values so Array/Drop types are not freed while still owned by the target.
- hir_lower: movedOutLocals + markMovedOutFromAst + shouldSkipDrop
- Nexus: drop zeroing workaround; free headers after each request
- examples/move_field.bux regression for Box { items: arr }
This commit is contained in:
@@ -153,13 +153,13 @@ module Http {
|
||||
/// Fallback when only raw bytes are available.
|
||||
pub func RawRequest_WantsKeepAlive(raw: String) -> bool {
|
||||
if String_Contains(raw, "Connection: close") || String_Contains(raw, "connection: close") ||
|
||||
String_Contains(raw, "CONNECTION: CLOSE") {
|
||||
String_Contains(raw, "CONNECTION: CLOSE") {
|
||||
return false;
|
||||
}
|
||||
if String_Contains(raw, "HTTP/1.0") {
|
||||
if String_Contains(raw, "Connection: keep-alive") ||
|
||||
String_Contains(raw, "Connection: Keep-Alive") ||
|
||||
String_Contains(raw, "connection: keep-alive") {
|
||||
String_Contains(raw, "Connection: Keep-Alive") ||
|
||||
String_Contains(raw, "connection: keep-alive") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -100,8 +100,8 @@ module Parser {
|
||||
|
||||
// Find header/body boundary
|
||||
let boundary: String = bux_strstr(raw, "\r\n\r\n");
|
||||
// Only one allocation path — avoid Array_New then overwrite (leak) and
|
||||
// suppress auto-drop after moving into HttpRequest (use-after-free).
|
||||
// Single assignment path (no Array_New then overwrite). Field-move of
|
||||
// `headers` into HttpRequest skips auto-Drop (compiler movedOutLocals).
|
||||
var headers: Array<HeaderEntry>;
|
||||
var body: String = "";
|
||||
if String_Len(boundary) > 0 {
|
||||
@@ -116,7 +116,7 @@ module Parser {
|
||||
}
|
||||
|
||||
if String_Eq(path, "") {
|
||||
// auto-drop of `headers` runs on return
|
||||
// auto-drop of `headers` runs on error return
|
||||
return ParseResult_NewErr(HttpError { tag: HttpError_BadRequest });
|
||||
}
|
||||
|
||||
@@ -127,11 +127,6 @@ module Parser {
|
||||
body: body,
|
||||
headers: headers,
|
||||
};
|
||||
// Ownership transferred into req — zero local shell so auto-drop is a no-op.
|
||||
// (Compiler does not yet treat field-move as a move-out of the local.)
|
||||
headers.data = null as *HeaderEntry;
|
||||
headers.len = 0;
|
||||
headers.cap = 0;
|
||||
return ParseResult_NewOk(req);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ module Server {
|
||||
import Std::Net::{Net_Create, Net_SetReuse, Net_Bind, Net_Listen, Net_Accept, Net_Send, Net_Recv, Net_Close, Net_LastError};
|
||||
import Std::String::{String_Len, String_StartsWith};
|
||||
import Std::Channel::{Channel, Channel_New, Channel_Send, Channel_Recv};
|
||||
import Std::Array::{Array_Drop};
|
||||
import Config::{ServerConfig};
|
||||
import Http::{HttpRequest, HttpResponse, Http_StatusText, Http_NewResponse, Request_WantsKeepAlive};
|
||||
import Http::{HttpRequest, HttpResponse, Http_StatusText, Http_NewResponse, Request_WantsKeepAlive, HeaderEntry};
|
||||
import Errors::{ParseResult};
|
||||
import Parser::{ParseRequest};
|
||||
import Router::{Router, Router_Dispatch};
|
||||
@@ -95,6 +96,8 @@ module Server {
|
||||
}
|
||||
let resp: HttpResponse = Router_Dispatch(router, req);
|
||||
Net_Send(fd, BuildResponse(resp, keepAlive));
|
||||
// Free header buffer (moved into req at parse; no Drop on nested fields)
|
||||
Array_Drop<HeaderEntry>(&req.headers);
|
||||
} else {
|
||||
let resp: HttpResponse = Http_NewResponse(400, "text/plain; charset=utf-8", "Bad Request");
|
||||
Net_Send(fd, BuildResponse(resp, false));
|
||||
|
||||
Reference in New Issue
Block a user