-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Description
Sorry in advanced for the really long program. I will try to come up with a simpler case which still triggers my error.
Here's the stacktrace:
Exception (9):
epc1=0x402204e2 epc2=0x00000000 epc3=0x00000000 excvaddr=0x40209dfa depc=0x00000000
ctx: sys
sp: 3ffffd80 end: 3fffffb0 offset: 01a0
>>>stack>>>
3fffff20: 4020e42a 887fcf5c 8574b2c2 28cf6a2a
3fffff30: 4020c0a0 3ffee358 3fff1d84 00000008
3fffff40: 40226b3a 3ffee358 3ffee358 3ffeb810
3fffff50: 3ffeb810 00000060 00000000 0000002f
3fffff60: 00000002 0000001a 4020c3f3 40211e09
3fffff70: 3ffef818 3ffeed30 03a71f63 60000600
3fffff80: 40211e4e 3fffdab0 00000000 3fffdcb0
3fffff90: 3ffeed40 3fffdab0 00000000 40201a13
3fffffa0: 40000f49 40000f49 3fffdab0 40000f49
<<<stack<<<
ets Jan 8 2013,rst cause:4, boot mode:(1,7)
wdt reset
And here it is decoded:
decoding 10 results
0x4020e42a: wDev_Get_Next_TBTT at ?? line ?
0x4020c0a0: wifi_fpm_do_wakeup at ?? line ?
0x40226b3a: send_server_hello_done at /Users/igrokhotkov/e/axtls/e1/ssl/tls1_svr.c line 363
: (inlined by) send_server_hello_sequence at /Users/igrokhotkov/e/axtls/e1/ssl/tls1_svr.c line 281
: (inlined by) do_svr_handshake at /Users/igrokhotkov/e/axtls/e1/ssl/tls1_svr.c line 80
0x4020c3f3: pp_noise_test at ?? line ?
0x40211e09: hostap_input at ?? line ?
0x40211e4e: hostap_input at ?? line ?
0x40201a13: uart_init at /home/tim/.arduino15/packages/esp8266/hardware/esp8266/2.3.0/cores/esp8266/uart.c line 336
Basic Infos
Hardware
Hardware: ESP-12
Core Version: 2.3.0
Description
I get an Exception (9)
error (LoadStoreAlignment
) when I use strncpy(groupNames[nameIdx], pos + 8, nameLen)
. Workarounds that I have found include declaring groupNames[][]
in the global scope, or copying the characters one by one in a for loop.
I've also had issues using calloc
on groupNames[i]
when I tried making it a dynamic 2D array, but I just wanted to focus on this error. Like I said, if I can figure out a smaller program that triggers this same error, I will either edit this post or upload the smaller program in the comments.
Settings in IDE
Module: Adafruit HUZZAH ESP8266
Flash Size: 4MB/1MB
CPU Frequency: 80Mhz
Flash Mode: qio
Flash Frequency: 40Mhz
Upload Using: SERIAL
Reset Method: nodemcu
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <FS.h>
#include <SPI.h>
#include <WiFiClientSecure.h>
#include <climits>
#include <ctype.h>
#include <string>
#include <algorithm>
#include <cctype>
// Hardware button press definitions
#define SINGLE_CLICK 1
#define DOUBLE_CLICK 2
#define HOLD_CLICK 3
#define CLICK_DELAY 500 // Max delay between double clicks in ms
#define HOLD_LENGTH 1000 // Button hold length in ms
// GroupMe definitions
#define KEY_LEN 41
#define SERVER "api.groupme.com"
#define HTTPS_PORT 443
#define GROUPME_INDEX 20
#define GROUPME_CREATE 21
#define GROUPME_ADD 22
#define GROUPME_MESSAGE 23
#define CONTACT_ID 24
#define CONTACT_NUM 25
#define CONTACT_EMAIL 26
// Fingerprint found using https://www.grc.com/fingerprints.htm
#define FINGERPRINT "ED:22:CB:A5:30:A8:BB:B0:C2:27:93:90:65:CD:64:EA:EA:18:3F:0E"
using namespace std;
WiFiClientSecure client;
uint32_t startTime = 0;
uint32_t prevStartTime = 0;
uint32_t currentTime;
uint8_t clickType = 0;
uint8_t userIdType;
uint32_t randNumber;
char singleClickMessage[141];
char doubleClickMessage[141];
char holdClickMessage[141];
char key[41];
string groupmeKey;
string groupName;
string groupDescription;
string groupUID;
string nickname;
string message;
string userId;
bool hasDescription;
bool shareGroup = false;
void groupmeRequest(uint8_t requestType)
{
char uid[11];
client.stop();
string request;
string requestBody;
bool getGroups = false;
if (client.connect(SERVER, HTTPS_PORT))
{
Serial.println("Connected!");
// Don't send information if the certificates don't match!
if (client.verify(FINGERPRINT, SERVER)) {
switch(requestType)
{
case GROUPME_INDEX:
request = request + "GET /v3/groups?per_page=1";
getGroups = true;
break;
// Create a new group:
// Required values: "name" - The name of this group
// Optional values: "description" - The description of this group
// "share" - Returns share link if true
// Need to save the group uid
case GROUPME_CREATE:
request = request + "POST /v3/groups";
requestBody = requestBody +
"{" +
" \"name\":\"" + groupName + "\"";
if (hasDescription)
{
requestBody = requestBody + "," +
" \"description\":\"" + groupDescription + "\"";
}
if (shareGroup)
{
requestBody = requestBody + "," +
" \"share\":true";
}
requestBody = requestBody +
"}";
client.println(requestBody.c_str());
break;
case GROUPME_ADD:
request = request + "POST /v3/groups/" + groupUID + "/members/add/";
requestBody = requestBody +
"{" +
" \"nickname\":\"" + nickname +"\"";
switch(userIdType)
{
case CONTACT_ID:
requestBody = requestBody + "\"user_id\":\"" + userId + "\"";
break;
case CONTACT_NUM:
requestBody = requestBody + "\"phone_number\":\"" + userId + "\"";
break;
case CONTACT_EMAIL:
requestBody = requestBody + "\"email\":\"" + userId + "\"";
break;
}
break;
case GROUPME_MESSAGE:
request = request + "POST /v3/groups/" + groupUID + "/messages";
sprintf(uid, "%d", random(UINT_MAX));
requestBody = requestBody +
"{" +
" \"message\": {\"" +
" \"source_guid\":\"" + uid + "\"" +
" \"text\": " + message + "\"" +
" }" +
"}";
// Remove all whitespace
//postData.erase(remove_if(postData.begin(), postData.end(), (int(*)(int))isspace), postData.end());
// Insert the message
//postData.replace(postData.rfind("%s"), 2, message);
// Insert the uid
//postData.replace(postData.find("%s"), 2, uid);
break;
}
uint8_t pageNum = 1;
char pageNumStr[2];
long timeOut = 4000; //capture response from the server
long lastTime = millis();
uint32_t bytesAvailable;
int readLen;
char c;
char response[1025] = {'\0'};
// By default, the request gets 1 "page" of results with 10 groups
// on the page. If we want more groups, we can either have multiple
// requests or increase the number of groups per page.
char *pos;
uint8_t idIdx = 0;
uint8_t nameIdx = 0;
uint8_t nameLen;
Serial.println("certificate matches");
while (getGroups)
{
if (getGroups)
{
sprintf(pageNumStr, "%d", pageNum);
Serial.println((request + "&page=" + pageNumStr + "&token=" + groupmeKey + " HTTP/1.1").c_str());
client.println((request + "&page=" + pageNumStr + "&token=" + groupmeKey + " HTTP/1.1").c_str());
pageNum++;
}
client.println("Host: api.groupme.com");
if (requestBody.size() > 0)
{
client.println("Content-Type: application/json");
client.print("Content-Length: ");
client.println(requestBody.size());
client.println();
client.println(requestBody.c_str());
}
client.println();
lastTime = millis();
// Get a maximum of 20 groups and group IDs
char groupIds[20][9] = {'\0'};
// Group names can be up to 255 characters in length
char groupNames[20][256] = {'\0'};
// There's some sort of dangling pointer or something...
while ((millis() - lastTime) < timeOut) //wait for incoming response
{
// Need to read in chunks because it's gonna be UUUUGGGEEEE
while ((bytesAvailable = client.available())) //characters incoming from server
{
if (bytesAvailable < 1024)
{
client.readBytes(response, bytesAvailable);
}
else
{
client.readBytes(response, 1024); //read characters
}
//Serial.print(response);
if (strstr(response, "Content-Length: 36"))
{
getGroups = false;
}
else
{
// Search the current string chunk for
// "group_id":"xxxxxxxx","name":"xxxxxxxxxxx"
// The problem we need to worry about is that this chunk
// might split up some of the needed data
// Find the pointer to the beginning of the group id key.
if (idIdx < 20)
{
pos = strstr(response, "\"group_id\":\"");
if (pos != NULL)// && pos + 12 + 8 < response + bytesAvailable)
{
strncpy(groupIds[idIdx], pos + 12, 8);
// Since the group ids may be less than 8 digits,
// remove any extraneous characters
for (uint8_t i = 0; i < 8; i++)
{
// Replace non digits with null terminators
if (!isdigit(groupIds[idIdx][i]))
{
groupIds[idIdx][i] = '\0';
break;
}
}
Serial.println(groupIds[idIdx]);
idIdx++;
}
}
// Find the pointer to the beginning of the group name
if (nameIdx < 20)
{
pos = strstr(response, "\"name\":\"");
if (pos != NULL && pos + 9 < response + bytesAvailable)
{
if (strstr(pos + 8, "\"") != NULL)
{
nameLen = (uint8_t) (strstr(pos + 8, "\"") - (pos + 8));
if (pos + 8 + nameLen < response + bytesAvailable)
{
// NOTE: THIS LINE IS CAUSING THE ERROR
strncpy(groupNames[nameIdx], pos + 8, nameLen);
for (int i = 0; i < nameLen; i++)
{
//groupNames[nameIdx][i] = pos[8 + i];
//Serial.print(groupNames[nameIdx][i]);
}
Serial.println(groupNames[nameIdx]);
}
nameIdx++;
}
}
}
}
}
}
}
} else {
Serial.println("certificate doesn't match");
}
}
else
{
Serial.println("Connection Failed");
}
Serial.println();
Serial.println("Request Complete!!");
}
void readPin()
{
// Button up
if (digitalRead(0) == HIGH)
{
if (prevStartTime != 0 && startTime - prevStartTime <= CLICK_DELAY)
{
clickType = DOUBLE_CLICK;
}
else if (millis() - startTime <= CLICK_DELAY)
{
clickType = SINGLE_CLICK;
}
}
// Button down
else
{
clickType = HOLD_CLICK;
prevStartTime = startTime;
startTime = millis();
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(1000);
//WiFiManager wifiManager;
WiFi.disconnect(true);
WiFi.begin("ssid", "password");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
string ssid("");
char id[10];
if (SPIFFS.begin()) {
File config = SPIFFS.open("/groupme", "r");
File js;
if (config)
{
Serial.println(config.size());
groupmeKey = config.readStringUntil('\n').c_str();
Serial.print("GroupMe API Key: ");
Serial.println(groupmeKey.c_str());
groupmeRequest(GROUPME_INDEX);
}
config.close();
SPIFFS.end();
attachInterrupt(digitalPinToInterrupt(0), readPin, CHANGE);
}
}
void loop() {
// put your main code here, to run repeatedly:
currentTime = millis();
if (clickType == DOUBLE_CLICK)
{
Serial.println("Double press");
clickType = 0;
}
else if (clickType == SINGLE_CLICK && currentTime - startTime > CLICK_DELAY)
{
Serial.println("Single press");
clickType = 0;
}
else if (clickType == HOLD_CLICK && currentTime - startTime > HOLD_LENGTH)
{
Serial.println("Button Hold");
clickType = 0;
}
}