Skip to content

pinMode() does not check valid pin number #149

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

Open
mikaelpatel opened this issue Feb 23, 2016 · 6 comments
Open

pinMode() does not check valid pin number #149

mikaelpatel opened this issue Feb 23, 2016 · 6 comments

Comments

@mikaelpatel
Copy link

The current pinMode() implementation performs a digitalPinToPort(pin) and then checks the port for NOT_A_PORT but digitalPinToPort() is a program memory table read. It is possible to give an illegal pin number.

Possible correction is:

void pinMode(uint8_t pin, uint8_t mode)
{
    if (pin >= NUM_DIGITAL_PINS) return;
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *reg, *out;
    ...
}

Replacing the port check with a pin number check (first).

Cheers!

@cousteaulecommandant
Copy link

This also affects digitalRead() and digitalWrite().

Honestly I have no idea how this check was supposed to work. It would have made sense if pins_arduino.h defined digital_pin_to_port_PGM as something like

const uint8_t PROGMEM digital_pin_to_port_PGM[256] = {
    /*  0 -  7 */ PD, PD, PD, PD, PD, PD, PD, PD, 
    /*  8 - 14 */ PB, PB, PB, PB, PB, PB, 
    /* 15 - 19 */ PC, PC, PC, PC, PC, PC
    /* 20 - 255: all zeros (NOT_A_PIN) */
};

so that if you queried it with a (uint8_t) pin from 20 to 255 you'd get 0, thus failing the if (port == NOT_A_PIN) return; check. But this is not the case since there's no [256] on the code, so trying to fetch any pin past that would either return "garbage values" or trigger some sort of undefined behavior.
(Fixing this by adding the 256 makes no sense though; that'd involve wasting a lot of memory. @mikaelpatel's solution makes much more sense.)

cousteaulecommandant referenced this issue in cousteaulecommandant/Arduino Mar 3, 2016
Fix for `pinMode()`, `digitalWrite()`, `digitalRead()` (issue #4605).
Current behavior: look up pin number in `digital_pin_to_port_PGM[]` and then check if it returned `NOT_A_PIN`.  Causes undefined behavior if provided `pin` number is out of the range of `digital_pin_to_port_PGM[]`.
Proposed behavior (from issue #4605): check if `pin` is within the valid range of `digital_pin_to_port_PGM[]`, and THEN look it up.

Additionally, remove second check for `port` not being `NOT_A_PIN` (which was useful for boards where the pin numbering skips some numbers).  This can still be achieved by making `bit = digitalPinToBitMask(pin)` be 0 for invalid pins, which causes further bitwise operations such as `*reg &= ~bit;` and `*out |= bit;` to not actually modify the value of the register.  (This removal makes the operation complete a bit faster for valid pins and slower for invalid pins, which I think is a good trade; plus it saves binary size.)
@per1234
Copy link
Contributor

per1234 commented Aug 18, 2017

What's the worst case result of passing an invalid pin number to one of these functions using Arduino AVR Boards if no checks at all were done?

Is it possible this could cause hardware damage on a board with no external connections or corrupt the firmware? If the answer is no then I think it would be best to just assume that the user is passing a valid pin number and remove the overhead of checking the validity of the value, including the current NOT_A_PIN check. If the user's code is messed up badly enough to be passing invalid pin values then they're going to be experiencing unexpected behavior regardless of any sanity checks so this provides no clear benefit and only adds overhead.

@cousteaulecommandant
Copy link

What's the worst case result of passing an invalid pin number to one of these functions using Arduino AVR Boards if no checks at all were done?

Well, looking up outside of the lookup table is undefined behavior, so in principle anything can happen.
In practice I don't think there would be electrical problems from the chip's side; outside of it it depends on what's connected but that could also cause trouble even without the check if the user enters the wrong pin number, so the check doesn't provide any guarantee.
In any case, I'd either do this check right or not do it at all, rather than leaving it as it is now. (Doing it right sounds safer, but I guess Arduino is "in a budget" when it comes to code size and speed.)

@sandeepmistry sandeepmistry transferred this issue from arduino/Arduino Sep 16, 2019
@neu-rah
Copy link

neu-rah commented Sep 16, 2019

#2

@aentinger
Copy link
Contributor

@mikaelpatel Good catch 👍 Could create a small PR for this?

@aentinger aentinger reopened this Sep 17, 2019
@cousteaulecommandant
Copy link

@mikaelpatel Good catch +1 Could create a small PR for this?

Back in the day I opened arduino/Arduino#4649, but it was closed after Chainsaw and never reopened.
Now there is #302 targeting the same issue (not sure how different it is or which approach is better, although I do remember my approach was more of a hack than a proper fix).

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

No branches or pull requests

5 participants