Skip to content

[stdlib] Prevent coercion from Bool to numerical types when decoding JSON and plist #11885

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

Merged
merged 1 commit into from
Sep 18, 2017

Conversation

cpwhidden
Copy link
Contributor

JSONEncoder and PropertyListEncoder both use NSNumber to box Bool values. An encoded Bool can be coerced to any numerical type during decoding because (false as NSNumber).intValue == 0. As a remedy, all of the unbox(_:as:) methods of _JSONDecoder and _PlistDecoder for numerical types include a check that the value is not identical to either kCFBooleanTrue or kCFBooleanFalse, and throw a DecodingError._typeMismatch(at:expectation:) if this check fails.

Right now, Swift can dangerously decode Bool data as a numeric type as in the following examples:

let arrayData = try! JSONEncoder().encode([false, true])
try! JSONDecoder().decode([Int].self, from: arrayData) // == [0,1]

let dictData = try! PropertyListEncoder().encode(["foo":false])
try! PropertyListDecoder().decode([String:Double].self, from: dictData) // == ["foo": 0.0]

struct Foo: Codable {
    let bar: Int
}
try! JSONDecoder().decode(Foo.self, from: JSONEncoder().encode(["bar":true])) // == Foo(bar: 1)

This issue has the potential to affect the correctness of many programs, and in particular programs that depend on the decoding system to validate the application-specific correctness of JSON. It could also be more troublesome for programs when unkeyed containers are used.

Note that currently the opposite is not an issue. Encoded numerical types cannot decode to Bool.

…ding JSON and plist

JSONEncoder and PropertyListEncoder both use NSNumber to box Bool values.  An encoded Bool can be coerced to any numerical type during decoding because (false as NSNumber).intValue == 0.  As a remedy, all of the unbox(_:as:) methods of _JSONDecoder and _PlistDecoder for numerical types include a check that the value is not identical to either kCFBooleanTrue or kCFBooleanFalse, and throw a DecodingError._typeMismatch(at:expectation:) if this check fails.
@CodaFi CodaFi requested a review from itaiferber September 17, 2017 18:53
@CodaFi
Copy link
Contributor

CodaFi commented Sep 17, 2017

(Drive-by CI pass, don't mind me)

@swift-ci please test

Copy link
Contributor

@itaiferber itaiferber left a comment

Choose a reason for hiding this comment

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

This looks good to me — this might have backwards-compatibility ramifications, but I think the correctness of this fix is more important. I don't think we ever wanted it to be possible to decode true or false as numeric types. Thanks for putting this together!

@itaiferber itaiferber merged commit 1457e4d into swiftlang:master Sep 18, 2017
norio-nomura added a commit to norio-nomura/ObjectEncoder that referenced this pull request Feb 27, 2018
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.

3 participants