Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eventfilter ternary logic consistency fixes #6393

Open
wants to merge 4 commits into
base: 1.4
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix(server): Event Filters use explicit Boolean casting for operands …
…of logical operators
  • Loading branch information
jpfr committed Apr 8, 2024
commit ca0fda7c8fdd7ed927f11837f09b3d886b5ea265
41 changes: 32 additions & 9 deletions src/server/ua_subscription_events_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
/* Ternary Logic
* -------------
* Similar to SQL, OPC UA Queries use the K3 - Strong Kleene Logic that
* considers ternary values true/false/null (unknown). Most operators resolve to
* a ternary value. Some operators can resolve to a literal value (e.g. CAST). */
* considers ternary values true/false/null (unknown). Every operator result
* (Variant) can be cast to a a ternary truth value. See the v2t method below.
* We cast all operands to a ternary truth value before a logical operator is
* applied. */

typedef enum {
UA_TERNARY_FALSE = -1,
Expand Down Expand Up @@ -50,13 +52,6 @@ UA_Ternary_not(UA_Ternary v) {
return (UA_Ternary)((int)v * -1);
}

static UA_Ternary v2t(const UA_Variant *v) {
if(UA_Variant_isEmpty(v) || !UA_Variant_hasScalarType(v, &UA_TYPES[UA_TYPES_BOOLEAN]))
return UA_TERNARY_NULL;
UA_Boolean b = *(UA_Boolean*)v->data;
return (b) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE;
}

static const UA_Boolean bFalse = false;
static const UA_Boolean bTrue = true;

Expand All @@ -77,6 +72,34 @@ static UA_Variant t2v(UA_Ternary t) {
return v;
}

/* Forward declarations */
static void
castNumerical(const UA_Variant *in, const UA_DataType *type, UA_Variant *out);
static UA_StatusCode
castImplicitFromString(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out);

/* For translating to a ternary truth-value we apply the rules for the "explicit
* casting" to a Boolean. Because implicit casting from numerical to Boolean is
* not possible as per Table 125 in the standard. */
static UA_Ternary v2t(const UA_Variant *v) {
/* Empty -> NULL, Arrays are undefined in the standard */
if(UA_Variant_isEmpty(v) || !UA_Variant_isScalar(v))
return UA_TERNARY_NULL;

/* Try to cast to Boolean. The variant remains empty if this fails.
* Otherwise the bTrue/bFalse singletons are set. */
UA_Variant vBool;
UA_Variant_init(&vBool);
if(v->type != &UA_TYPES[UA_TYPES_STRING])
castNumerical(v, &UA_TYPES[UA_TYPES_BOOLEAN], &vBool);
else
castImplicitFromString(v, &UA_TYPES[UA_TYPES_BOOLEAN], &vBool);

if(!vBool.type)
return UA_TERNARY_NULL;
return (vBool.data == &bTrue) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE;
}

/* Type Casting Rules
* ------------------
* For comparison operations values from different datatypes can be implicitly
Expand Down
Loading