ColdFusion 9: int and type="numeric" nasty bug?
Asked Answered
S

2

1

I've just experienced a behaviour that defies any logic and could potentially lead to serious issues and was wondering if it was a bug or if the behaviour was itended and what are the best practices to circumvent the issue? If it's a bug, is there a patch?

Here's the two wierd behaviours that when put together are a threat to any system's data integrity.

  1. int('1 2') -> 41276
  2. isValid('numeric', '1 2') -> true

Why? Well let's see...

<cffunction name="deleteSomething" access="public" returntype="void">
    <cfargument name="somethingId" type="numeric" required="yes">

    <cfquery datasource="#dsn()#">
        DELETE
        FROM Something
        WHERE id = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.somethingId#">;   
    </cfquery>

</cffunction>


<cfset deleteSomething('1 2')>

Here, the type="numeric" arguments validation (which perhaps is based on the same algorithm as isValid?) doesn't throw with '1 2'. Even worse, cfqueryparam cfsqltype="cf_sql_integer" seems to be using int to convert the value which will end up being 41276.

In other words, deleteSomething('1 2') will delete the entity with id 41276 instead of throwing an exception since the value 1 2 is obviously not numeric.

Now, the only fix I thought of is to perform additionnal argument validation using isValid('integer', ... or a regular expression, but that's a real pain and besides, I never understood why they haven't implemented type="integer"?

Obviously, I also always made the false assumption that cfqueryparam type="cf_sql_integer" would validate that the value passed is a valid integer.

EDIT:

It seems that even isvalid('integer', ... is also not reliable as we can see in
Why isvalid("integer","1,5") = YES?

EDIT2:

I know that I could add additionnal arguments validation for every expected integer argument in every function, however that would require to fix a huge code base in my case and it's also very error-prone. It also makes the built-in argument validation completely useless in this case.

I would rather prefer a solution where I could create and apply an unofficial patch. Is that a realistic option? If so I would like to be pointed out in the right direction.

EDIT3: It doesn't solves all the problems, but CF11 added support for a strictNumberValidation application level configuration.

"Starting from ColdFusion 11, this function evaluates on a more strict basis. Setting this value to false makes the isValid function to behave in the older way. This setting effects cfargument, cfparam and cfform tags wherever integer & numeric validation is used. Based on this setting, the validation reflects in those tags as well."

Squadron answered 2/10, 2013 at 15:5 Comment(6)
Duplicate question of: https://mcmap.net/q/889521/-why-isvalid-quot-integer-quot-quot-1-5-quot-yes seems like adobe aren't fixing this.Katzen
@Jarede, Thanks for the reference. However I believe that my question highlights a few more anomalies and isin't a duplicate.Squadron
if you look at the related SO question, it does pretty much answer everything you brought up. see @Mike Causer answer for specifics.Katzen
I discovered that isValid("variablename") testing for a ColdFusion variable name disregards spaces too in CF8, 9 & 10. isValid("variablename", " abc ") evaluates as a "valid" ColdFusion variable name even though there are leading & trailing spaces.Dunigan
The isDate() function isn't much better. It returns true for "april 31".Gramme
@Katzen It's not the kind of answer I am looking for. I still hope that there are better alternatives that I haven't already thought of and described in the problematic.Squadron
E
2

This is a variation on that theme from the other question. See this code (or run it on cflive.net):

<cfscript>
s = "1 2";
i = int(s);
v = isValid("numeric", s);
d = createOdbcDate(s);
writeDump([s,i,v,d]);
</cfscript>

s converts to 41276 when calling int(), and when using it as an input for createOdbcDate(), we get:

January, 02 2013 00:00:00 +0000

So "1 2" is being interpreted as "m d", with an implied year of the current year.

Which is utterly stupid. But there you go.

Erv answered 2/10, 2013 at 15:52 Comment(7)
Would there be any way to create and apply an unofficial patch? In this case, that behaviour makes built-it argument validation completely useless.Squadron
@JamesMohler, Not really. The issue is having to fix an extremely huge code base and the unecessary overhead that is implied by performing an additionnal type checking for every expected integer argument. I would definitely prefer fixing the issue at it's core.Squadron
@AdamCameron Could you have a look at my first comment?Squadron
No, there's no way I am aware of to patch ColdFusion "unofficially". As to how you might adjust your approach so as to mitigate it, we'd have to understand how it is you come to be using a string like that in the way you are (which seems a bit odd, TBH). Perhaps a new question here, with more details?Erv
@AdamCameron I'm not using a string and the example's API is designed to take numeric values. However, because of that bug, if a developer makes a mistake and pass something like '1 2', CF will not complain and that would be pretty hard to debug. Therefore, that makes the built-in argument validation pretty useless for that case.Squadron
@plalx: '1 2' is a string.Erv
@AdamCameron That's my point... not sure what you are trying to say? What I am saying is that if there was a bug in the system and somehow a string like that would get passed to an API like above, CF would not complain and the function would correctly execute since the string would get converted to an integer by cfqueryparam. That kind of bug would be pretty hard to find because of CF's inability to do it's job properly. It's quite incredible there's no fix for this, other than re-validating the argument within the function's body.Squadron
C
0

You can use regular expressions to find out if there are any non numeric characters in a given form field:

reFind( "[^\d-]", "1 2")

That will match any character that is not a number, not a -

If you want to check only positive numbers, you can use

reFind( "[^\d]", "1 2")    

If this returns true, you do not have an integer.

Conflict answered 2/10, 2013 at 18:2 Comment(3)
Thanks, but I've already stated that solution in the question.Squadron
--0---0-- is not a number; checking whether input is a signed integer with a regex would be better done with NOT refind( "^-?\d+$" , input ) ... for the second one, \D is a shortcut for [^\d]Rubberneck
Good point. That will learn me to not write regex to quickly.Conflict

© 2022 - 2024 — McMap. All rights reserved.