KurtE
Senior Member+
@Paul (and) others...
I have been hit by this before and with working on head start to maybe extend the File/FS classes in follow on releases.
If anyone currently creates their own implementation of the File class and they do not override all of the virtual functions,
All sketches that use this File class will build just fine, however in the majority of cases, this will lead to fault if one of these
functions is called. Example bogus sketch:
This sketch builds fine. And as the code suggests it will go boom:
The problem: All of these methods are implemented like:
Now if I call it directly: (f) will be nullptr and as such it returns 0...
However in the wrapped case( File wrap(&bfile); ) f is not null, so it calls through null pointer.
Note: the wrapping is normal here... As for example from LittleFS you see things like:
Now where it is hitting me is suppose you wish to extend the File class, example:
Without changing any additional code all of the current File Classes will build without issue, but calling these new methods will blow up this way...
So question is how to avoid going BOOM? Yes hopefully will have all new implementations for our known File classes, BUT if we miss any than...
Actually I see the issue:
So when I call through from the wrapper class where f points to in my case: boomFile class, which you now incremented the count to 1, which is in the same memory location as f...
1 is not NULLPTR so you try call through it...
So probably get rid of union?
I have been hit by this before and with working on head start to maybe extend the File/FS classes in follow on releases.
If anyone currently creates their own implementation of the File class and they do not override all of the virtual functions,
All sketches that use this File class will build just fine, however in the majority of cases, this will lead to fault if one of these
functions is called. Example bogus sketch:
Code:
#include <FS.h>
class boomFile : public File {
public:
boomFile(const char *name) : name_(name) {};
private:
const char *name_;
};
void setup() {
while (!Serial) ;
Serial.begin(115200);
Serial.print(CrashReport);
Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
boomFile bfile("GoBoom");
delay(250);
Serial.println("direct file no boom"); Serial.flush();
while(Serial.read() == -1) ;
while(Serial.read() != -1) ;
Serial.println(bfile.position(), DEC); Serial.flush();
Serial.println("wrapped file - press any key to go BOOM"); Serial.flush();
while (Serial.read() == -1) ;
File wrap(&bfile);
Serial.println(wrap.position(), DEC);
delay(250);
Serial.println("Don't expect this line to print");
}
void loop() {
}
Code:
CrashReport:
A problem occurred at (system time) 8:54:10
Code was executing from address 0xB3C
CFSR: 82
(DACCVIOL) Data Access Violation
(MMARVALID) Accessed Address: 0x1 (nullptr)
Check code at 0xB3C - very likely a bug!
Run "addr2line -e mysketch.ino.elf 0xB3C" for filename & line number.
Temperature inside the chip was 49.43 °C
Startup CPU clock speed is 600MHz
Reboot was caused by auto reboot after fault or bad interrupt detected
C:\Users\kurte\Documents\Arduino\abc\abc.ino Aug 28 2021 08:54:00
direct file no boom
The problem: All of these methods are implemented like:
Code:
virtual uint64_t position() {
return (f) ? f->position() : 0;
}
However in the wrapped case( File wrap(&bfile); ) f is not null, so it calls through null pointer.
Note: the wrapping is normal here... As for example from LittleFS you see things like:
Code:
return File(new LittleFSFile(&lfs, dir, filepath));
Now where it is hitting me is suppose you wish to extend the File class, example:
Code:
virtual bool getAccessDateTime(uint16_t* pdate, uint16_t* ptime) {
return (f) ? f->getAccessDateTime(pdate, ptime) : false;
}
So question is how to avoid going BOOM? Yes hopefully will have all new implementations for our known File classes, BUT if we miss any than...
Actually I see the issue:
Code:
private:
void invalidate() {
if (f && --(f->refcount) == 0) delete f;
}
union {
// instances of base File class use this pointer
File *f;
// instances of derived classes (which actually access media)
// use this reference count which is managed by the base class
unsigned int refcount;
};
1 is not NULLPTR so you try call through it...
So probably get rid of union?