Fix deep-review findings for prepare/closed-handle safety

Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/c2c0f3ef-f641-4d83-94f8-a3cd3ede6db8

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-05-15 12:04:40 +00:00
committed by GitHub
parent 4cc82e2fda
commit 639bfe3246
5 changed files with 134 additions and 36 deletions

View File

@@ -27,13 +27,17 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeNewEngine(
#[no_mangle]
pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClone(
_env: EnvUnowned,
env: EnvUnowned,
_class: JClass,
engine_ptr: jlong,
) -> jlong {
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
let c = engine.clone();
Box::into_raw(Box::new(c)) as jlong
let res = throw_err(env, |_env| {
let engine = unsafe { &mut *get_engine_ptr(engine_ptr)? };
let c = engine.clone();
Ok(Box::into_raw(Box::new(c)) as jlong)
});
res.unwrap_or_default()
}
#[no_mangle]
@@ -43,7 +47,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativePrepare(
engine_ptr: jlong,
) {
let _ = throw_err(env, |_env| {
let engine = unsafe { &mut *(engine_ptr as *mut Engine) };
let engine = unsafe { &mut *get_engine_ptr(engine_ptr)? };
engine.prepare()?;
Ok(())
});
@@ -450,6 +454,9 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine(
_class: JClass,
engine_ptr: jlong,
) {
if engine_ptr == 0 {
return;
}
unsafe {
let _engine = Box::from_raw(engine_ptr as *mut Engine);
}
@@ -829,6 +836,13 @@ fn throw_err<T>(mut env: EnvUnowned, f: impl FnOnce(&mut Env) -> Result<T>) -> R
}
}
fn get_engine_ptr(engine_ptr: jlong) -> Result<*mut Engine> {
if engine_ptr == 0 {
return Err(anyhow::anyhow!("Engine is closed"));
}
Ok(engine_ptr as *mut Engine)
}
fn get_string_array(env: &mut Env, array: jobjectArray) -> Result<Vec<String>> {
if array.is_null() {
return Ok(Vec::new());

View File

@@ -46,7 +46,7 @@ public class Engine implements AutoCloseable, Cloneable {
// Pointer to Engine allocated on Rust's heap, all native methods works on
// engine expects this pointer. It is free'd in `close` method.
private final long enginePtr;
private long enginePtr;
/**
* Creates a new Regorus Engine.
@@ -64,7 +64,7 @@ public class Engine implements AutoCloseable, Cloneable {
* Efficiently clones an Engine.
*/
public Engine clone() {
return new Engine(nativeClone(enginePtr));
return new Engine(nativeClone(requireOpen()));
}
/**
@@ -72,7 +72,7 @@ public class Engine implements AutoCloseable, Cloneable {
* Optional: if skipped, first evaluation performs the same setup.
*/
public void prepare() {
nativePrepare(enginePtr);
nativePrepare(requireOpen());
}
/**
@@ -82,7 +82,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public void setRegoV0(boolean enable) {
nativeSetRegoV0(enginePtr, enable);
nativeSetRegoV0(requireOpen(), enable);
}
/**
@@ -94,7 +94,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @return Rego package defined in the policy.
*/
public String addPolicy(String filename, String rego) {
return nativeAddPolicy(enginePtr, filename, rego);
return nativeAddPolicy(requireOpen(), filename, rego);
}
/**
@@ -105,7 +105,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @return Rego package defined in the policy.
*/
public String addPolicyFromFile(String path) {
return nativeAddPolicyFromFile(enginePtr, path);
return nativeAddPolicyFromFile(requireOpen(), path);
}
/**
@@ -114,7 +114,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @return List of Rego packages as a JSON array of strings.
*/
public String getPackages() {
return nativeGetPackages(enginePtr);
return nativeGetPackages(requireOpen());
}
/**
@@ -123,14 +123,14 @@ public class Engine implements AutoCloseable, Cloneable {
* @return List of Rego policies as a JSON array of sources.
*/
public String getPolicies() {
return nativeGetPolicies(enginePtr);
return nativeGetPolicies(requireOpen());
}
/**
* Clears the data document.
*/
public void clearData() {
nativeClearData(enginePtr);
nativeClearData(requireOpen());
}
/**
@@ -152,7 +152,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @param data Inline data document.
*/
public void addDataJson(String data) throws RuntimeException {
nativeAddDataJson(enginePtr, data);
nativeAddDataJson(requireOpen(), data);
}
/**
@@ -169,7 +169,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @param path Path to JSON data document.
*/
public void addDataJsonFromFile(String path) throws RuntimeException {
nativeAddDataJsonFromFile(enginePtr, path);
nativeAddDataJsonFromFile(requireOpen(), path);
}
/**
@@ -178,7 +178,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @param input inline JSON input.
*/
public void setInputJson(String input) {
nativeSetInputJson(enginePtr, input);
nativeSetInputJson(requireOpen(), input);
}
/**
@@ -187,7 +187,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @param path Path to JSON input.
*/
public void setInputJsonFromFile(String path) {
nativeSetInputJsonFromFile(enginePtr, path);
nativeSetInputJsonFromFile(requireOpen(), path);
}
/**
@@ -198,7 +198,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @return Query results as a JSON string.
*/
public String evalQuery(String query) {
return nativeEvalQuery(enginePtr, query);
return nativeEvalQuery(requireOpen(), query);
}
/**
@@ -209,7 +209,7 @@ public class Engine implements AutoCloseable, Cloneable {
* @return Value of the rule as a JSON string.
*/
public String evalRule(String rule) {
return nativeEvalRule(enginePtr, rule);
return nativeEvalRule(requireOpen(), rule);
}
/**
@@ -219,7 +219,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public void setEnableCoverage(boolean enable) {
nativeSetEnableCoverage(enginePtr, enable);
nativeSetEnableCoverage(requireOpen(), enable);
}
/**
@@ -227,7 +227,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public void clearCoverageData() {
nativeClearCoverageData(enginePtr);
nativeClearCoverageData(requireOpen());
}
/**
@@ -237,7 +237,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public String getCoverageReport() {
return nativeGetCoverageReport(enginePtr);
return nativeGetCoverageReport(requireOpen());
}
/**
@@ -247,7 +247,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public String getCoverageReportPretty() {
return nativeGetCoverageReportPretty(enginePtr);
return nativeGetCoverageReportPretty(requireOpen());
}
/**
@@ -257,7 +257,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public void setGatherPrints(boolean b) {
nativeSetGatherPrints(enginePtr, b);
nativeSetGatherPrints(requireOpen(), b);
}
/**
@@ -267,7 +267,7 @@ public class Engine implements AutoCloseable, Cloneable {
*
*/
public String takePrints() {
return nativeTakePrints(enginePtr);
return nativeTakePrints(requireOpen());
}
/**
@@ -276,24 +276,34 @@ public class Engine implements AutoCloseable, Cloneable {
* @param config Policy length configuration.
*/
public void setPolicyLengthConfig(PolicyLengthConfig config) {
nativeSetPolicyLengthConfig(enginePtr, config.maxCol, config.maxFileBytes, config.maxLines);
nativeSetPolicyLengthConfig(requireOpen(), config.maxCol, config.maxFileBytes, config.maxLines);
}
/**
* Clear the policy length configuration, reverting to defaults.
*/
public void clearPolicyLengthConfig() {
nativeClearPolicyLengthConfig(enginePtr);
nativeClearPolicyLengthConfig(requireOpen());
}
long getPtr() {
return requireOpen();
}
private long requireOpen() {
if (enginePtr == 0) {
throw new IllegalStateException("Engine is closed");
}
return enginePtr;
}
@Override
public void close() {
nativeDestroyEngine(enginePtr);
if (enginePtr != 0) {
nativeDestroyEngine(enginePtr);
enginePtr = 0;
}
}
// Loading native library from JAR is adapted from:

View File

@@ -44,4 +44,28 @@ public class EngineTest extends TestCase
Map expression = (Map) expressions.get(0);
Assert.assertEquals("Hello, World!", expression.get("value"));
}
public void test_closed_engine_operations_throw()
{
Engine engine = new Engine();
engine.close();
try {
engine.prepare();
fail("prepare should fail on closed engine");
} catch (IllegalStateException expected) {
}
try {
engine.clone();
fail("clone should fail on closed engine");
} catch (IllegalStateException expected) {
}
try {
engine.evalQuery("data");
fail("evalQuery should fail on closed engine");
} catch (IllegalStateException expected) {
}
}
}