This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 209f73ff0e1a03ccad2589e014b263976892338c
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Jul 31 14:18:32 2026 +0200

    drivers/power: Do not call gauge methods a driver did not implement.
    
    Every BATIOC_* case in the gauge upper half calls dev->ops->X() after
    checking only that the *argument* pointer is non-NULL.  The operations
    themselves are optional -- max1704x.c implements four of the eight, and
    the in-tree fake gauge leaves chipid and operate NULL -- so asking a gauge
    for something it does not provide calls through a NULL pointer.
    
    On ARM that is not a null dereference but a branch to address 0, which has
    the Thumb bit clear: the core takes a usage fault with CFSR bit 17,
    INVSTATE, escalated to a hard fault.  From userspace it looks like the
    program stopped mid-run for no reason, and on a board whose assert path
    delays before resetting it looks like a hang.
    
    Guard all eight.  A missing method is now ENOTTY, which is what the default
    case already returns for an unrecognised command and what a caller can
    sensibly probe for.
    
    Tested on sim:nsh with the fake gauge and a local test app.  Before the
    change, ioctl(BATIOC_CHIPID) kills the simulator with SIGSEGV.  After the
    change, BATIOC_CHIPID and BATIOC_OPERATE return ENOTTY and
    BATIOC_VOLTAGE still returns the voltage.  nucleo-f412zg:nsh with
    BATTERY_GAUGE, MAX1704X, BQ27426 and BATTERY_FAKE_GAUGE builds.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 drivers/power/battery/battery_gauge.c | 96 +++++++++++++++++++++++++++++------
 1 file changed, 80 insertions(+), 16 deletions(-)

diff --git a/drivers/power/battery/battery_gauge.c 
b/drivers/power/battery/battery_gauge.c
index 101cca01c66..fbd52a293db 100644
--- a/drivers/power/battery/battery_gauge.c
+++ b/drivers/power/battery/battery_gauge.c
@@ -313,10 +313,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR int *ptr = (FAR int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->state(dev, ptr);
+              break;
             }
+
+          if (dev->ops->state == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->state(dev, ptr);
         }
         break;
 
@@ -324,10 +332,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR bool *ptr = (FAR bool *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->online(dev, ptr);
+              break;
             }
+
+          if (dev->ops->online == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->online(dev, ptr);
         }
         break;
 
@@ -335,10 +351,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR int *ptr = (FAR int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->voltage(dev, ptr);
+              break;
             }
+
+          if (dev->ops->voltage == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->voltage(dev, ptr);
         }
         break;
 
@@ -346,10 +370,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR int *ptr = (FAR int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->capacity(dev, ptr);
+              break;
             }
+
+          if (dev->ops->capacity == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->capacity(dev, ptr);
         }
         break;
 
@@ -357,10 +389,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR int *ptr = (FAR int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->current(dev, ptr);
+              break;
             }
+
+          if (dev->ops->current == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->current(dev, ptr);
         }
         break;
 
@@ -368,10 +408,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR int *ptr = (FAR int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->temp(dev, ptr);
+              break;
             }
+
+          if (dev->ops->temp == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->temp(dev, ptr);
         }
         break;
 
@@ -379,10 +427,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR unsigned int *ptr = (FAR unsigned int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->chipid(dev, ptr);
+              break;
             }
+
+          if (dev->ops->chipid == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->chipid(dev, ptr);
         }
         break;
 
@@ -390,10 +446,18 @@ static int bat_gauge_ioctl(FAR struct file *filep,
         {
           FAR int *ptr = (FAR int *)((uintptr_t)arg);
 
-          if (ptr)
+          if (ptr == NULL)
             {
-              ret = dev->ops->operate(dev, ptr);
+              break;
             }
+
+          if (dev->ops->operate == NULL)
+            {
+              ret = -ENOTTY;
+              break;
+            }
+
+          ret = dev->ops->operate(dev, ptr);
         }
         break;
 

Reply via email to