Skip to content

Commit

Permalink
Merge pull request duckdb#8871 from lnkuiper/fuzzer_stuff
Browse files Browse the repository at this point in the history
Fix some fuzzer issues
  • Loading branch information
Mytherin authored Sep 20, 2023
2 parents 474a0bd + 0d7e0fa commit 756d6ea
Show file tree
Hide file tree
Showing 20 changed files with 202 additions and 46 deletions.
2 changes: 2 additions & 0 deletions .github/config/uncovered_files.csv
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ core_functions/scalar/date/date_part.cpp 17
core_functions/scalar/date/date_sub.cpp 209
core_functions/scalar/date/date_trunc.cpp 23
core_functions/scalar/date/strftime.cpp 10
core_functions/scalar/date/time_bucket.cpp 3
core_functions/scalar/enum/enum_functions.cpp 10
core_functions/scalar/generic/current_setting.cpp 1
core_functions/scalar/generic/least.cpp 2
Expand Down Expand Up @@ -543,6 +544,7 @@ optimizer/pushdown/pushdown_inner_join.cpp 2
optimizer/pushdown/pushdown_set_operation.cpp 2
optimizer/regex_range_filter.cpp 2
optimizer/remove_unused_columns.cpp 2
optimizer/rule/arithmetic_simplification.cpp 1
optimizer/rule/date_part_simplification.cpp 2
optimizer/rule/distributivity.cpp 3
optimizer/rule/empty_needle_removal.cpp 2
Expand Down
10 changes: 4 additions & 6 deletions extension/json/json_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ namespace duckdb {
using JSONPathType = JSONCommon::JSONPathType;

static JSONPathType CheckPath(const Value &path_val, string &path, size_t &len) {
if (path_val.IsNull()) {
throw InvalidInputException("JSON path cannot be NULL");
}
const auto path_str_val = path_val.DefaultCastAs(LogicalType::VARCHAR);
auto path_str = path_str_val.GetValueUnsafe<string_t>();
len = path_str.GetSize();
Expand Down Expand Up @@ -49,7 +46,7 @@ unique_ptr<FunctionData> JSONReadFunctionData::Copy() const {
}

bool JSONReadFunctionData::Equals(const FunctionData &other_p) const {
auto &other = (const JSONReadFunctionData &)other_p;
auto &other = other_p.Cast<JSONReadFunctionData>();
return constant == other.constant && path == other.path && len == other.len && path_type == other.path_type;
}

Expand All @@ -60,7 +57,7 @@ unique_ptr<FunctionData> JSONReadFunctionData::Bind(ClientContext &context, Scal
string path = "";
size_t len = 0;
JSONPathType path_type = JSONPathType::REGULAR;
if (arguments[1]->return_type.id() != LogicalTypeId::SQLNULL && arguments[1]->IsFoldable()) {
if (arguments[1]->IsFoldable()) {
constant = true;
const auto path_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]);
path_type = CheckPath(path_val, path, len);
Expand All @@ -83,7 +80,7 @@ unique_ptr<FunctionData> JSONReadManyFunctionData::Copy() const {
}

bool JSONReadManyFunctionData::Equals(const FunctionData &other_p) const {
auto &other = (const JSONReadManyFunctionData &)other_p;
auto &other = other_p.Cast<JSONReadManyFunctionData>();
return paths == other.paths && lens == other.lens;
}

Expand All @@ -100,6 +97,7 @@ unique_ptr<FunctionData> JSONReadManyFunctionData::Bind(ClientContext &context,
vector<string> paths;
vector<size_t> lens;
auto paths_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]);

for (auto &path_val : ListValue::GetChildren(paths_val)) {
paths.emplace_back("");
lens.push_back(0);
Expand Down
14 changes: 8 additions & 6 deletions extension/json/json_functions/json_transform.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
#include "json_transform.hpp"

#include "duckdb/common/enum_util.hpp"
#include "duckdb/common/serializer/deserializer.hpp"
#include "duckdb/common/serializer/serializer.hpp"
#include "duckdb/common/types.hpp"
#include "duckdb/execution/expression_executor.hpp"
#include "duckdb/function/cast/cast_function_set.hpp"
#include "duckdb/function/cast/default_casts.hpp"
#include "duckdb/function/scalar/nested_functions.hpp"
#include "json_functions.hpp"
#include "json_scan.hpp"
#include "duckdb/common/serializer/serializer.hpp"
#include "duckdb/common/serializer/deserializer.hpp"

namespace duckdb {

Expand Down Expand Up @@ -72,12 +72,13 @@ static unique_ptr<FunctionData> JSONTransformBind(ClientContext &context, Scalar
if (arguments[1]->HasParameter()) {
throw ParameterNotResolvedException();
}
if (arguments[1]->return_type == LogicalTypeId::SQLNULL) {
bound_function.return_type = LogicalTypeId::SQLNULL;
} else if (!arguments[1]->IsFoldable()) {
if (!arguments[1]->IsFoldable()) {
throw BinderException("JSON structure must be a constant!");
}
auto structure_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]);
if (structure_val.IsNull() || arguments[1]->return_type == LogicalTypeId::SQLNULL) {
bound_function.return_type = LogicalTypeId::SQLNULL;
} else {
auto structure_val = ExpressionExecutor::EvaluateScalar(context, *arguments[1]);
if (!structure_val.DefaultTryCastAs(JSONCommon::JSONType())) {
throw BinderException("Cannot cast JSON structure to string");
}
Expand Down Expand Up @@ -741,6 +742,7 @@ bool JSONTransform::Transform(yyjson_val *vals[], yyjson_alc *alc, Vector &resul

switch (result_type.id()) {
case LogicalTypeId::SQLNULL:
FlatVector::Validity(result).SetAllInvalid(count);
return true;
case LogicalTypeId::BOOLEAN:
return TransformNumerical<bool>(vals, result, count, options);
Expand Down
2 changes: 1 addition & 1 deletion src/core_functions/function_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ static StaticFunctionDefinition internal_functions[] = {
DUCKDB_AGGREGATE_FUNCTION(RegrSXXFun),
DUCKDB_AGGREGATE_FUNCTION(RegrSXYFun),
DUCKDB_AGGREGATE_FUNCTION(RegrSYYFun),
DUCKDB_SCALAR_FUNCTION(RepeatFun),
DUCKDB_SCALAR_FUNCTION_SET(RepeatFun),
DUCKDB_SCALAR_FUNCTION(ReplaceFun),
DUCKDB_AGGREGATE_FUNCTION_SET(ReservoirQuantileFun),
DUCKDB_SCALAR_FUNCTION(ReverseFun),
Expand Down
3 changes: 0 additions & 3 deletions src/core_functions/scalar/date/date_part.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1317,9 +1317,6 @@ static unique_ptr<FunctionData> DatePartBind(ClientContext &context, ScalarFunct
}

Value part_value = ExpressionExecutor::EvaluateScalar(context, *arguments[0]);
if (part_value.IsNull()) {
return nullptr;
}
const auto part_name = part_value.ToString();
switch (GetDatePartSpecifier(part_name)) {
case DatePartSpecifier::JULIAN_DAY:
Expand Down
3 changes: 3 additions & 0 deletions src/core_functions/scalar/generic/hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ namespace duckdb {

static void HashFunction(DataChunk &args, ExpressionState &state, Vector &result) {
args.Hash(result);
if (args.AllConstant()) {
result.SetVectorType(VectorType::CONSTANT_VECTOR);
}
}

ScalarFunction HashFun::GetFunction() {
Expand Down
2 changes: 1 addition & 1 deletion src/core_functions/scalar/string/functions.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@
"parameters": "string,count",
"description": "Repeats the string count number of times",
"example": "repeat('A', 5)",
"type": "scalar_function"
"type": "scalar_function_set"
},
{
"name": "replace",
Expand Down
13 changes: 8 additions & 5 deletions src/core_functions/scalar/string/repeat.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#include "duckdb/core_functions/scalar/string_functions.hpp"

#include "duckdb/common/exception.hpp"
#include "duckdb/common/vector_operations/binary_executor.hpp"
#include "duckdb/core_functions/scalar/string_functions.hpp"

#include <string.h>
#include <ctype.h>
#include <string.h>

namespace duckdb {

Expand Down Expand Up @@ -33,8 +32,12 @@ static void RepeatFunction(DataChunk &args, ExpressionState &state, Vector &resu
});
}

ScalarFunction RepeatFun::GetFunction() {
return ScalarFunction({LogicalType::VARCHAR, LogicalType::BIGINT}, LogicalType::VARCHAR, RepeatFunction);
ScalarFunctionSet RepeatFun::GetFunctions() {
ScalarFunctionSet repeat;
for (const auto &type : {LogicalType::VARCHAR, LogicalType::BLOB}) {
repeat.AddFunction(ScalarFunction({type, LogicalType::BIGINT}, type, RepeatFunction));
}
return repeat;
}

} // namespace duckdb
12 changes: 3 additions & 9 deletions src/execution/reservoir_sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,25 +107,19 @@ void ReservoirSamplePercentage::AddToReservoir(DataChunk &input) {
if (append_to_next_sample > 0) {
// we need to also add to the next sample
DataChunk new_chunk;
new_chunk.Initialize(allocator, input.GetTypes());
SelectionVector sel(append_to_current_sample_count);
for (idx_t r = 0; r < append_to_current_sample_count; r++) {
sel.set_index(r, r);
}
new_chunk.Slice(sel, append_to_current_sample_count);
new_chunk.InitializeEmpty(input.GetTypes());
new_chunk.Slice(input, *FlatVector::IncrementalSelectionVector(), append_to_current_sample_count);
new_chunk.Flatten();

current_sample->AddToReservoir(new_chunk);
} else {
input.Flatten();

input.SetCardinality(append_to_current_sample_count);
current_sample->AddToReservoir(input);
}
}
if (append_to_next_sample > 0) {
// slice the input for the remainder
SelectionVector sel(STANDARD_VECTOR_SIZE);
SelectionVector sel(append_to_next_sample);
for (idx_t i = 0; i < append_to_next_sample; i++) {
sel.set_index(i, append_to_current_sample_count + i);
}
Expand Down
19 changes: 10 additions & 9 deletions src/function/function_binder.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#include "duckdb/function/function_binder.hpp"
#include "duckdb/common/limits.hpp"

#include "duckdb/planner/expression/bound_cast_expression.hpp"
#include "duckdb/planner/expression/bound_aggregate_expression.hpp"
#include "duckdb/planner/expression/bound_function_expression.hpp"
#include "duckdb/planner/expression/bound_constant_expression.hpp"
#include "duckdb/catalog/catalog.hpp"
#include "duckdb/catalog/catalog_entry/scalar_function_catalog_entry.hpp"

#include "duckdb/planner/expression_binder.hpp"
#include "duckdb/common/limits.hpp"
#include "duckdb/execution/expression_executor.hpp"
#include "duckdb/function/aggregate_function.hpp"
#include "duckdb/function/cast_rules.hpp"
#include "duckdb/catalog/catalog.hpp"
#include "duckdb/planner/expression/bound_aggregate_expression.hpp"
#include "duckdb/planner/expression/bound_cast_expression.hpp"
#include "duckdb/planner/expression/bound_constant_expression.hpp"
#include "duckdb/planner/expression/bound_function_expression.hpp"
#include "duckdb/planner/expression_binder.hpp"

namespace duckdb {

Expand Down Expand Up @@ -268,7 +268,8 @@ unique_ptr<Expression> FunctionBinder::BindScalarFunction(ScalarFunctionCatalogE

if (bound_function.null_handling == FunctionNullHandling::DEFAULT_NULL_HANDLING) {
for (auto &child : children) {
if (child->return_type == LogicalTypeId::SQLNULL) {
if (child->return_type == LogicalTypeId::SQLNULL ||
(child->IsFoldable() && ExpressionExecutor::EvaluateScalar(context, *child).IsNull())) {
return make_uniq<BoundConstantExpression>(Value(LogicalType::SQLNULL));
}
}
Expand Down
3 changes: 0 additions & 3 deletions src/function/scalar/string/like.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,6 @@ static unique_ptr<FunctionData> LikeBindFunction(ClientContext &context, ScalarF
D_ASSERT(arguments.size() == 2 || arguments.size() == 3);
if (arguments[1]->IsFoldable()) {
Value pattern_str = ExpressionExecutor::EvaluateScalar(context, *arguments[1]);
if (pattern_str.IsNull()) {
return nullptr;
}
return LikeMatcher::CreateLikeMatcher(pattern_str.ToString());
}
return nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ struct RepeatFun {
static constexpr const char *Description = "Repeats the string count number of times";
static constexpr const char *Example = "repeat('A', 5)";

static ScalarFunction GetFunction();
static ScalarFunctionSet GetFunctions();
};

struct ReplaceFun {
Expand Down
9 changes: 9 additions & 0 deletions test/fuzzer/duckfuzz/hash_constant.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# name: test/fuzzer/duckfuzz/hash_constant.test
# description: Hashing constants should yield a constant vector (duckdb-fuzzer #290)
# group: [duckfuzz]

statement ok
create table all_types as select * exclude(small_enum, medium_enum, large_enum) from test_all_types();

statement ok
SELECT hash(main.list_value(main.list_value(), main.list_value(42, 999, NULL, NULL, -42), NULL, main.list_value(), main.list_value(42, 999, NULL, NULL, -42))) FROM all_types;
4 changes: 2 additions & 2 deletions test/fuzzer/duckfuzz/json_extract_null.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require json
statement ok
PRAGMA enable_verification

statement error
query I
SELECT json_extract('hello world', CAST(NULL AS json)) AS c1
----
JSON path cannot be NULL
NULL
33 changes: 33 additions & 0 deletions test/fuzzer/duckfuzz/json_functions_null_params.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# name: test/fuzzer/duckfuzz/json_functions_null_params.test
# description: JSON functions with parameters that evaluate to NULL (duckdb-fuzzer #294 and #319)
# group: [duckfuzz]

require json

statement ok
PRAGMA enable_verification

query I
SELECT from_json('{"duck": 42}', NULL::JSON)
----
NULL

query I
SELECT json_extract('{"duck": 42}', NULL::VARCHAR[])
----
NULL

query I
SELECT json_keys('{"duck": 42}', NULL::VARCHAR[])
----
NULL

query I
SELECT json_valid(NULL)
----
NULL

query I
SELECT json_extract('{"duck": 42}', NULL::VARCHAR)
----
NULL
14 changes: 14 additions & 0 deletions test/fuzzer/duckfuzz/reservoir_issues.test_slow
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# name: test/fuzzer/duckfuzz/reservoir_issues.test_slow
# description: Issues with reservoir sampling and uninitialized memory (duckdb-fuzzer #324 and #861)
# group: [duckfuzz]

require tpch

statement ok
call dbgen(sf=0.1)

statement ok
SELECT * FROM lineitem USING SAMPLE 91.0% (Reservoir)

statement ok
SELECT c13 FROM lineitem AS t17(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16) GROUP BY ALL USING SAMPLE 72.0% (Reservoir)
10 changes: 10 additions & 0 deletions test/fuzzer/sqlsmith/json_contains_null.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ query I
SELECT json_contains(NULL::VARCHAR, NULL::VARCHAR);
----
NULL

query I
WITH cte AS (
SELECT NULL::VARCHAR j
FROM range(1)
)
SELECT json_contains(j, j)
FROM cte
----
NULL
10 changes: 10 additions & 0 deletions test/sql/function/date/test_date_part.test
Original file line number Diff line number Diff line change
Expand Up @@ -578,3 +578,13 @@ endloop
endloop

endloop

query T
WITH cte AS (
SELECT NULL::VARCHAR part
FROM range(1)
)
SELECT date_part(part, TIMESTAMP '2019-01-06 04:03:02')
FROM cte
----
NULL
10 changes: 10 additions & 0 deletions test/sql/function/date/test_date_trunc.test
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,13 @@ SELECT stats(date_trunc('${daypart}', d)) FROM timestamps LIMIT 1;
[Min: -infinity, Max: infinity][Has Null: false, Has No Null: true]

endloop

query T
WITH cte AS (
SELECT NULL::VARCHAR part
FROM range(1)
)
SELECT date_trunc(part, TIMESTAMP '2019-01-06 04:03:02')
FROM cte
----
NULL
Loading

0 comments on commit 756d6ea

Please sign in to comment.