Skip to content

Commit 8d4c261

Browse files
committed
Added bounds to checking in digitalPinTo* functions
1 parent c8d6aef commit 8d4c261

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

cores/arduino/Arduino.h

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -169,24 +169,51 @@ extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
169169
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
170170
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
171171
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
172+
extern const uint8_t digital_pin_count;
173+
174+
#define NOT_A_PIN 0
175+
#define NOT_A_PORT 0
176+
177+
#define NOT_AN_INTERRUPT -1
172178

173179
// Get the bit location within the hardware port of the given virtual pin.
174180
// This comes from the pins_*.c file for the active board configuration.
175181
//
176182
// These perform slightly better as macros compared to inline functions
177-
//
178-
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
179-
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
180-
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
183+
//
181184
#define analogInPinToBit(P) (P)
182185
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
183186
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
184187
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
185-
186-
#define NOT_A_PIN 0
187-
#define NOT_A_PORT 0
188-
189-
#define NOT_AN_INTERRUPT -1
188+
//
189+
// bounds checking on these functions because they return a pointer to an address that will be modified.
190+
// An out of bounds write can result in stack corruption and fun to track-down errors.
191+
//
192+
static inline const uint8_t digitalPinToPort(const uint8_t P) {
193+
if (P > digital_pin_count) {
194+
return NOT_A_PIN;
195+
} else {
196+
return pgm_read_byte( digital_pin_to_port_PGM + P );
197+
}
198+
}
199+
static inline const uint8_t digitalPinToBitMask(const uint8_t P) {
200+
if (P > digital_pin_count) {
201+
return NOT_A_PIN;
202+
} else {
203+
return pgm_read_byte( digital_pin_to_bit_mask_PGM + P );
204+
}
205+
}
206+
static inline const uint8_t digitalPinToTimer(const uint8_t P) {
207+
if (P > digital_pin_count) {
208+
return NOT_A_PIN;
209+
} else {
210+
return pgm_read_byte( digital_pin_to_timer_PGM + P );
211+
}
212+
}
213+
// these defines are to maintain backwards compatibility with #ifdef
214+
#define digitalPinToPort digitalPinToPort
215+
#define digitalPinToBitMask digitalPinToBitMask
216+
#define digitalPinToTimer digitalPinToTimer
190217

191218
#ifdef ARDUINO_MAIN
192219
#define PA 1

cores/arduino/wiring_digital.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include "wiring_private.h"
2727
#include "pins_arduino.h"
2828

29+
const uint8_t digital_pin_count = sizeof(digital_pin_to_port_PGM) / sizeof(digital_pin_to_port_PGM[0]);
30+
2931
void pinMode(uint8_t pin, uint8_t mode)
3032
{
3133
uint8_t bit = digitalPinToBitMask(pin);

variants/circuitplay32u4/pins_arduino.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ const uint8_t PROGMEM analog_pin_to_channel_PGM[] = {
341341
9 // A11 D12 PD6 ADC9
342342
};
343343

344+
extern const uint8_t digital_pin_count;
345+
344346
#endif /* ARDUINO_MAIN */
345347

346348
// These serial port names are intended to allow libraries and architecture-neutral

0 commit comments

Comments
 (0)