mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Fix parsing numbers from null-terminated buffers (#2755)
This commit is contained in:
		
				
					committed by
					
						 Jesse Hills
						Jesse Hills
					
				
			
			
				
	
			
			
			
						parent
						
							980b7cda8f
						
					
				
				
					commit
					8e1c9f5042
				
			| @@ -73,51 +73,52 @@ AnovaPacket *AnovaCodec::get_stop_request() { | ||||
| } | ||||
|  | ||||
| void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||
|   memset(this->buf_, 0, 32); | ||||
|   strncpy(this->buf_, (char *) data, length); | ||||
|   char buf[32]; | ||||
|   memset(buf, 0, sizeof(buf)); | ||||
|   strncpy(buf, (char *) data, std::min<uint16_t>(length, sizeof(buf) - 1)); | ||||
|   this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false; | ||||
|   switch (this->current_query_) { | ||||
|     case READ_DEVICE_STATUS: { | ||||
|       if (!strncmp(this->buf_, "stopped", 7)) { | ||||
|       if (!strncmp(buf, "stopped", 7)) { | ||||
|         this->has_running_ = true; | ||||
|         this->running_ = false; | ||||
|       } | ||||
|       if (!strncmp(this->buf_, "running", 7)) { | ||||
|       if (!strncmp(buf, "running", 7)) { | ||||
|         this->has_running_ = true; | ||||
|         this->running_ = true; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     case START: { | ||||
|       if (!strncmp(this->buf_, "start", 5)) { | ||||
|       if (!strncmp(buf, "start", 5)) { | ||||
|         this->has_running_ = true; | ||||
|         this->running_ = true; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     case STOP: { | ||||
|       if (!strncmp(this->buf_, "stop", 4)) { | ||||
|       if (!strncmp(buf, "stop", 4)) { | ||||
|         this->has_running_ = true; | ||||
|         this->running_ = false; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     case READ_TARGET_TEMPERATURE: { | ||||
|       this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f); | ||||
|       this->target_temp_ = parse_number<float>(buf, sizeof(buf)).value_or(0.0f); | ||||
|       if (this->fahrenheit_) | ||||
|         this->target_temp_ = ftoc(this->target_temp_); | ||||
|       this->has_target_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case SET_TARGET_TEMPERATURE: { | ||||
|       this->target_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f); | ||||
|       this->target_temp_ = parse_number<float>(buf, sizeof(buf)).value_or(0.0f); | ||||
|       if (this->fahrenheit_) | ||||
|         this->target_temp_ = ftoc(this->target_temp_); | ||||
|       this->has_target_temp_ = true; | ||||
|       break; | ||||
|     } | ||||
|     case READ_CURRENT_TEMPERATURE: { | ||||
|       this->current_temp_ = parse_number<float>(this->buf_, sizeof(this->buf_)).value_or(0.0f); | ||||
|       this->current_temp_ = parse_number<float>(buf, sizeof(buf)).value_or(0.0f); | ||||
|       if (this->fahrenheit_) | ||||
|         this->current_temp_ = ftoc(this->current_temp_); | ||||
|       this->has_current_temp_ = true; | ||||
| @@ -125,8 +126,8 @@ void AnovaCodec::decode(const uint8_t *data, uint16_t length) { | ||||
|     } | ||||
|     case SET_UNIT: | ||||
|     case READ_UNIT: { | ||||
|       this->unit_ = this->buf_[0]; | ||||
|       this->fahrenheit_ = this->buf_[0] == 'f'; | ||||
|       this->unit_ = buf[0]; | ||||
|       this->fahrenheit_ = buf[0] == 'f'; | ||||
|       this->has_unit_ = true; | ||||
|       break; | ||||
|     } | ||||
|   | ||||
| @@ -70,7 +70,6 @@ class AnovaCodec { | ||||
|   bool has_current_temp_; | ||||
|   bool has_unit_; | ||||
|   bool has_running_; | ||||
|   char buf_[32]; | ||||
|   bool fahrenheit_; | ||||
|  | ||||
|   CurrentQuery current_query_; | ||||
|   | ||||
| @@ -32,7 +32,7 @@ void EZOSensor::update() { | ||||
| } | ||||
|  | ||||
| void EZOSensor::loop() { | ||||
|   uint8_t buf[20]; | ||||
|   uint8_t buf[21]; | ||||
|   if (!(this->state_ & EZO_STATE_WAIT)) { | ||||
|     if (this->state_ & EZO_STATE_SEND_TEMP) { | ||||
|       int len = sprintf((char *) buf, "T,%0.3f", this->tempcomp_); | ||||
| @@ -74,7 +74,7 @@ void EZOSensor::loop() { | ||||
|   if (buf[0] != 1) | ||||
|     return; | ||||
|  | ||||
|   float val = parse_number<float>((char *) &buf[1], sizeof(buf) - 1).value_or(0); | ||||
|   float val = parse_number<float>((char *) &buf[1], sizeof(buf) - 2).value_or(0); | ||||
|   this->publish_state(val); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -362,45 +362,47 @@ std::string str_sanitize(const std::string &str); | ||||
| /// @name Parsing & formatting | ||||
| ///@{ | ||||
|  | ||||
| /// Parse a unsigned decimal number. | ||||
| /// Parse an unsigned decimal number (requires null-terminated string). | ||||
| template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0> | ||||
| optional<T> parse_number(const char *str, size_t len) { | ||||
|   char *end = nullptr; | ||||
|   unsigned long value = ::strtoul(str, &end, 10);  // NOLINT(google-runtime-int) | ||||
|   if (end == nullptr || end != str + len || value > std::numeric_limits<T>::max()) | ||||
|   if (end == str || *end != '\0' || value > std::numeric_limits<T>::max()) | ||||
|     return {}; | ||||
|   return value; | ||||
| } | ||||
| /// Parse an unsigned decimal number. | ||||
| template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_unsigned<T>::value), int> = 0> | ||||
| optional<T> parse_number(const std::string &str) { | ||||
|   return parse_number<T>(str.c_str(), str.length()); | ||||
|   return parse_number<T>(str.c_str(), str.length() + 1); | ||||
| } | ||||
| /// Parse a signed decimal number. | ||||
| /// Parse a signed decimal number (requires null-terminated string). | ||||
| template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0> | ||||
| optional<T> parse_number(const char *str, size_t len) { | ||||
|   char *end = nullptr; | ||||
|   signed long value = ::strtol(str, &end, 10);  // NOLINT(google-runtime-int) | ||||
|   if (end == nullptr || end != str + len || value < std::numeric_limits<T>::min() || | ||||
|       value > std::numeric_limits<T>::max()) | ||||
|   if (end == str || *end != '\0' || value < std::numeric_limits<T>::min() || value > std::numeric_limits<T>::max()) | ||||
|     return {}; | ||||
|   return value; | ||||
| } | ||||
| /// Parse a signed decimal number. | ||||
| template<typename T, enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), int> = 0> | ||||
| optional<T> parse_number(const std::string &str) { | ||||
|   return parse_number<T>(str.c_str(), str.length()); | ||||
|   return parse_number<T>(str.c_str(), str.length() + 1); | ||||
| } | ||||
| /// Parse a decimal floating-point number. | ||||
| /// Parse a decimal floating-point number (requires null-terminated string). | ||||
| template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0> | ||||
| optional<T> parse_number(const char *str, size_t len) { | ||||
|   char *end = nullptr; | ||||
|   float value = ::strtof(str, &end); | ||||
|   if (end == nullptr || end != str + len || value == HUGE_VALF) | ||||
|   if (end == str || *end != '\0' || value == HUGE_VALF) | ||||
|     return {}; | ||||
|   return value; | ||||
| } | ||||
| /// Parse a decimal floating-point number. | ||||
| template<typename T, enable_if_t<(std::is_same<T, float>::value), int> = 0> | ||||
| optional<T> parse_number(const std::string &str) { | ||||
|   return parse_number<T>(str.c_str(), str.length()); | ||||
|   return parse_number<T>(str.c_str(), str.length() + 1); | ||||
| } | ||||
|  | ||||
| ///@} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user