Skip to content

Conversation

@ralphlange
Copy link
Member

fixes #43

Comment on lines 834 to 835
// Doesn't mask "hidden" bytes (after NUL) for the sake of efficiency
// For string scalars, size == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, this comment is just pointing out that this will still return some false negetives and print a log, depending on the junk bytes behind the null. So this is an improvement but not perfect?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.
Doing min(strlen(), MAX_LENGTH) for every element seemed excessive.

SINGLE_TYPE_COMPARE(string, MAX_STRING_SIZE);
// Doesn't mask "hidden" bytes (after NUL) for the sake of efficiency
// For string scalars, size == 1
return memcmp(pa->v_string, pb->v_string, size*MAX_STRING_SIZE) == 0;
Copy link
Contributor

@mdavidsaver mdavidsaver Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some guarantee that bytes following a terminating nil will also be nil? eg. does "foo\0blah" equal "foo\0\0\0\0\0"? memcmp() will say "no", strncmp() will say "yes".

Also, the preceding macro and switch statement could be mostly replaced by use of dbValueSize().

Something like:

size_t size = pLogData->is_array ? pLogData->old_log_size : 1;
if(pLogData->type==DBR_STRING) {
    for(size_t i=0; i<size; i++) {
        if(strncmp(pa->a_string[i], pb->a_string[i], MAX_STRING_SIZE)!=0) {
            return 1;
        }
    }
} else {
    return memcmp(pa, pb, size*dbValueSize(pLogData->type))!=0;
}
return 0;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some guarantee that bytes following a terminating nil will also be nil? eg. does "foo\0blah" equal "foo\0\0\0\0\0"? memcmp() will say "no", strncmp() will say "yes".

No, there isn't. (See above.)
I found doing multiple memcmp/strncmp excessive, maybe it's not.
Given that arrays of strings are pretty rare...

Also, the preceding macro and switch statement could be mostly replaced by use of dbValueSize().

Something like:

size_t size = pLogData->is_array ? pLogData->old_log_size : 1;
if(pLogData->type==DBR_STRING) {
    for(size_t i=0; i<size; i++) {
        if(strncmp(pa->a_string[i], pb->a_string[i], MAX_STRING_SIZE)!=0)) {
            return 1;
        }
    }
} else {
    return memcmp(pa, pb, size*dbValueSize(pLogData->type))!=0;
}
return 0;

That's clearly beyond the original scope of this fix, but very reasonable.

Copy link
Contributor

@mdavidsaver mdavidsaver Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there isn't. (See above.)

Ah, now that exchange registers with me.

imo. there seems almost no point to memcmp() past the first terminating nil. The chances of a successful equality seem vanishing small ($\frac{1}{256^N}$), statistically similar to just return 1.

@ralphlange ralphlange changed the title JsonLogTask: fix string comparisons JsonLogTask: fix/improve value comparisons Dec 2, 2025
- fix string comparison (was comparing pointers) (fixes epics-modules#43)
- improve value comparison code
- REF improve name of compare function
Copy link
Member

@anjohnson anjohnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much simpler, LGTM!

@ralphlange
Copy link
Member Author

Superseded by #50

@ralphlange ralphlange closed this Dec 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Comparison for strings is always false (changed)

4 participants