Skip to content

Commit 6f09233

Browse files
authored
Merge pull request #171 from influxdata/crepererum/more-evil
test: extend evil test suite
2 parents 149ed38 + c1f2f9a commit 6f09233

File tree

17 files changed

+1768
-38
lines changed

17 files changed

+1768
-38
lines changed

guests/evil/src/common.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Methods used by multiple payloads.
2+
3+
use std::sync::Arc;
4+
5+
use datafusion_common::Result as DataFusionResult;
6+
use datafusion_expr::ScalarUDFImpl;
7+
8+
/// Return empty root file system.
9+
///
10+
/// This always returns [`None`] because the example does not need any files.
11+
pub(crate) fn root_empty() -> Option<Vec<u8>> {
12+
None
13+
}
14+
15+
/// Returns empty list of UDFs.
16+
///
17+
/// The passed `source` is ignored.
18+
#[expect(clippy::unnecessary_wraps, reason = "public API through export! macro")]
19+
pub(crate) fn udfs_empty(_source: String) -> DataFusionResult<Vec<Arc<dyn ScalarUDFImpl>>> {
20+
Ok(vec![])
21+
}

guests/evil/src/env.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! Payload that tries to read environment variables.
2+
use std::{hash::Hash, sync::Arc};
3+
4+
use arrow::datatypes::DataType;
5+
use datafusion_common::{Result as DataFusionResult, ScalarValue};
6+
use datafusion_expr::{ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility};
7+
8+
/// UDF that produces a string.
9+
struct StringUdf {
10+
/// Name.
11+
name: &'static str,
12+
13+
/// String producer.
14+
effect: Box<dyn Fn() -> Option<String> + Send + Sync>,
15+
16+
/// Signature of the UDF.
17+
///
18+
/// We store this here because [`ScalarUDFImpl::signature`] requires us to return a reference.
19+
signature: Signature,
20+
}
21+
22+
impl StringUdf {
23+
/// Create new UDF.
24+
fn new<F>(name: &'static str, effect: F) -> Self
25+
where
26+
F: Fn() -> Option<String> + Send + Sync + 'static,
27+
{
28+
Self {
29+
name,
30+
effect: Box::new(effect),
31+
signature: Signature::uniform(0, vec![], Volatility::Immutable),
32+
}
33+
}
34+
}
35+
36+
impl std::fmt::Debug for StringUdf {
37+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38+
let Self {
39+
name,
40+
effect: _,
41+
signature,
42+
} = self;
43+
44+
f.debug_struct("StringUdf")
45+
.field("name", name)
46+
.field("effect", &"<EFFECT>")
47+
.field("signature", signature)
48+
.finish()
49+
}
50+
}
51+
52+
impl PartialEq<Self> for StringUdf {
53+
fn eq(&self, other: &Self) -> bool {
54+
self.name == other.name
55+
}
56+
}
57+
58+
impl Eq for StringUdf {}
59+
60+
impl Hash for StringUdf {
61+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
62+
self.name.hash(state);
63+
}
64+
}
65+
66+
impl ScalarUDFImpl for StringUdf {
67+
fn as_any(&self) -> &dyn std::any::Any {
68+
self
69+
}
70+
71+
fn name(&self) -> &str {
72+
self.name
73+
}
74+
75+
fn signature(&self) -> &Signature {
76+
&self.signature
77+
}
78+
79+
fn return_type(&self, _arg_types: &[DataType]) -> DataFusionResult<DataType> {
80+
Ok(DataType::Utf8)
81+
}
82+
83+
fn invoke_with_args(&self, _args: ScalarFunctionArgs) -> DataFusionResult<ColumnarValue> {
84+
Ok(ColumnarValue::Scalar(ScalarValue::Utf8((self.effect)())))
85+
}
86+
}
87+
88+
/// Returns our evil UDFs.
89+
///
90+
/// The passed `source` is ignored.
91+
#[expect(clippy::unnecessary_wraps, reason = "public API through export! macro")]
92+
pub(crate) fn udfs(_source: String) -> DataFusionResult<Vec<Arc<dyn ScalarUDFImpl>>> {
93+
Ok(vec![
94+
Arc::new(StringUdf::new("args", || {
95+
let vars = std::env::args().collect::<Vec<_>>();
96+
if vars.is_empty() {
97+
None
98+
} else {
99+
Some(vars.join(","))
100+
}
101+
})),
102+
Arc::new(StringUdf::new("current_dir", || {
103+
let d = std::env::current_dir().unwrap();
104+
Some(d.display().to_string())
105+
})),
106+
Arc::new(StringUdf::new("current_exe", || {
107+
let e = std::env::current_exe().unwrap_err();
108+
Some(e.to_string())
109+
})),
110+
Arc::new(StringUdf::new("env", || {
111+
let vars = std::env::vars()
112+
.map(|(k, v)| format!("{k}:{v}"))
113+
.collect::<Vec<_>>();
114+
if vars.is_empty() {
115+
None
116+
} else {
117+
Some(vars.join(","))
118+
}
119+
})),
120+
])
121+
}

0 commit comments

Comments
 (0)