A string inside a struct is being overwritten and I can't tell why - c

I've had this problem for the last two hours and I can't understand what's happening. I expect it to print this
ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM
COPYRIGHT 2075-2077 ROBCO INDUSTRIES
-Server 6-
But instead it displays this
ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM
COPYRIGHT Testing testing 123
I have no clue why this is happening but hopefully you will be able to help me. (If you want to know what this is for it's a Fallout Terminal Emulator). Just ask if you nned any more details. Thanks!
It's being compiled like this if you need to know
gcc test.c configParser.c -lconfig
test.c
#include <stdio.h>
#include "robco.h"
int main() {
struct config_struct config;
config = getConfig("test_config.cfg");
printf("%s", config.banner);
return 0;
}
configParser.c
#include <stdio.h>
#include <libconfig.h>
#include <string.h>
#include "robco.h"
int cap(int num, int cap) {
return (num > cap) ? cap : num;
}
struct config_struct getConfig(const char *filename)
{
config_t cfg;
config_setting_t *root, *menu, *options, *option;
// Read the file. If there is an error, report it and exit.
config_init(&cfg);
config_read_file(&cfg, filename);
root = config_root_setting(&cfg);
// Get the banner from the config file if it exists, if not use the default set in robco.h
const char *banner;
if (! config_setting_lookup_string(root, "banner", &banner) ) {
banner = DEFAULT_BANNER;
}
// Create the config struct and fill in the banner
struct config_struct config;
strcpy(config.banner, banner);
// Get the menu
menu = config_lookup(&cfg, "menu");
// If it can't fetch the menu for any reason return -1
if(! menu) {
return;
}
// Get the options
options = config_setting_get_member(menu, "options");
if(! options) {
return;
}
// Get number of options
config.menu.num_options = cap(config_setting_length(options), MAX_OPTIONS);
// Get the title. If it doesn't exist use the default
const char *title;
if (! config_setting_lookup_string(menu, "title", &title) ) {
title = DEFAULT_TITLE;
}
strcpy(config.menu.title, title);
// Loop through and get the text for all the options
for(int i = 0; i < config.menu.num_options; ++i)
{
option = config_setting_get_elem(options, i);
const char *text;
config_setting_lookup_string(option, "text", &text);
strcpy(config.menu.options[i].text, text);
}
return config;
}
robco.h
#define MAX_STRING_LENGTH 52
#define MAX_OPTIONS 5
#define DEFAULT_BANNER "ROBCO INDUSTRIES UNIFIED OPERATING SYSTEM\nCOPYRIGHT 2075-2077 ROBCO INDUSTRIES\n-Server 6-"
#define DEFAULT_TITLE "-=- TEST TITLE -=-"
struct option_struct {
char text[MAX_STRING_LENGTH];
};
struct menu_struct {
struct option_struct options[MAX_OPTIONS];
int num_options;
int selected;
char title[MAX_STRING_LENGTH];
};
struct config_struct {
char banner[MAX_STRING_LENGTH];
struct menu_struct menu;
};
void printCenter(char msg[], int startRow);
void printMenuOption(char msg[], int startRow);
void drawMenu(struct menu_struct menu, int startRow);
void init_graphics();
struct config_struct getConfig(const char *filename);
test_config.cfg
menu: {
title: "Super Secret Valve Control Panel";
options: (
{
text: "Testing testing 123";
},
{
text: "THE SUN IS A DEADLY LASER";
}
);
};

I bet your MAX_STRING_LENGTH is too little and that you don't test for lengths. You must use strncpy and then don't forget to set the terminating null, which strncpy doesn't do.
You must also turn the warnings of your compiler on. I see struct config_struct getConfig but in that function you do some returns without a return value. The compiler should warn about that.

Your default banner text is longer than MAX_STRING_LENGTH, so when you copy it to config.banner you write past the end of the array, leading to undefined behavior.
Make sure all your buffers are large enough to store the longest string you expect (accounting for the terminator), or truncate strings to the length of the buffer, or use dynamic memory and size the buffers as you need to.

Related

C mutating struct properties by reference

I'm learning pointers in C and i came across a confusion between pointers X struts X functions
The goal: creating two structs and mutate properties inside them.
The path I'm going: I am creating these two structs and then passing its memory addresses to the mutate function, the function then prints and mutates some properties of these structs.
Result I get:
1: The name of the struct created is nod being entirely printed and its of the wrong struct passed, and the life property is not properly changed and printed to the screen.
2: On the terminal I get "Segmentation Fault", not sure why but I'm pretty sure its something wrong I did.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int power;
int life;
char name[];
} Hero;
void attackHero(Hero *hero, int *power) {
(*hero).life = (*hero).life - *power;
printf("Damage: %d\n", *power);
printf("Attacked hero: %s\n", (*hero).name);
printf("Hero's remaining life: %d\n", (*hero).life);
};
int main () {
Hero flash;
flash.power = 250;
flash.life = 500;
strcpy(flash.name, "The Flash");
Hero batman;
batman.power = 380;
batman.life = 700;
strcpy(batman.name, "Batman arkham knight");
attackHero(&flash, &batman.power);
return 0;
}
Result printed to the terminal (Vscode + gcc):
Here is the warning that I get when I compile your original code:
1.c:25:2: warning: ‘__builtin_memcpy’ writing 10 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
25 | strcpy(flash.name, "The Flash");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.c:30:2: warning: ‘__builtin_memcpy’ writing 21 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=]
30 | strcpy(batman.name, "Batman arkham knight");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to use the flexible array then you have to allocate space for it like this:
int main () {
Hero *flash = malloc(sizeof(*flash) + sizeof("The Flash"));
flash->power = 250;
flash->life = 500;
strcpy(flash->name, "The Flash");
Hero *batman = malloc(sizeof(*flash) + sizeof("Batman arkham knight"));
batman->power = 380;
batman->life = 700;
strcpy(batman->name, "Batman arkham knight");
attackHero(flash, &batman->power);
free(flash);
free(batman);
}
Here there the resulting code refactored a bit, and I added a error check for malloc:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int power;
int life;
char name[];
} Hero;
Hero *createHero(int power, int life, const char *name) {
Hero *h = malloc(sizeof(*h) + strlen(name) + 1);
if(!h) {
printf("malloc failed\n");
exit(1);
}
h->power = power;
h->life = life;
strcpy(h->name, name);
return h;
}
void attackHero(Hero *hero, int power) {
hero->life -= power;
printf(
"Damage: %d\n"
"Attacked hero: %s\n"
"Hero's remaining life: %d\n",
power,
hero->name,
hero->life
);
};
int main(void) {
Hero *flash = createHero(250, 500, "The Flash");
Hero *batman = createHero(380, 700, "Batman arkham knight");
attackHero(flash, batman->power);
free(flash);
free(batman);
}
Alternatively use a fixed array (char [64] as suggested by #Diego) or a char * and allocate space to it. The former only needs 2 lines of code change from the original:
// largest name in use
#define NAME_LEN sizeof("Batman arkham knight")
typedef struct {
int power;
int life;
char name[NAME_LEN];
} Hero;
Whole lotta malloc() going on. Since the hero’s names are string literals (and assuming they don’t change), just change name[]; to const char *name in the structure and initialize via simple assignment:
flash.name = "The Flash";
batman.name = "Batman arkham knight";
No worries about malloc() failures, name sizes or free() requirements.

Malloc for char** results in a corrupted top size

I am making a config reader for an application I am making. What I am trying to fix is that whenever I add another entry '{}' to the config, it will break the application. I have pinpointed the problem, but have no idea how to go about this.
C (config.c):
#include <config.h>
struct Config read_config(char * cfg) {
struct Config newCfg;
newCfg.valuesSize = 0;
int configIsMalloc = 0;
char * config;
if (file_exists(cfg)==0) {
config = cfg;
}
else {
config = read_file(cfg);
configIsMalloc=1;
}
newCfg.values = (char****)malloc(sizeof(char****)*strlen(config));
int valuesPtr = 0;
int needsMalloc = 1;
while(config) {
char * nextLine = strchr(config, '\n');
if (nextLine) *nextLine = '\0';
printf("%s\n", config);
if (config[0] == '{') {
if (needsMalloc==0) {
//newCfg.values[newCfg.valuesSize] = (char***)realloc(newCfg.values[newCfg.valuesSize], newCfg.valuesSize*(sizeof(char***)*sizeof(config)));
}
else {
newCfg.values[newCfg.valuesSize] = (char***)malloc(sizeof(char***)*strlen(config));
needsMalloc=0;
}
}
else if (strstr(config, "}")) {
newCfg.valuesSize++;
valuesPtr=0;
}
// The culprit lies here...
else if (strstr(config, ":")) {
newCfg.values[newCfg.valuesSize][valuesPtr] = (char**)malloc(1000);
char * split = strtok(config, ":");
newCfg.values[newCfg.valuesSize][valuesPtr][0] = (char*)malloc(strlen(split)*sizeof(char));
strcat(newCfg.values[newCfg.valuesSize][valuesPtr][0], split);
split = strtok(NULL, ":");
newCfg.values[newCfg.valuesSize][valuesPtr][1] = (char*)malloc(sizeof(split)*sizeof(char));
strcat(newCfg.values[newCfg.valuesSize][valuesPtr][1], split);
valuesPtr++;
}
if (nextLine) *nextLine = '\n';
config = nextLine ? (nextLine+1) : NULL;
}
(configIsMalloc==1) ? free(config) : NULL;
return newCfg;
}
config.h defines the struct for storing config information C (config.h):
#ifndef CONFIG_H
#define CONFIG_H
#include <string.h>
#include <stdlib.h>
#include <files.h>
struct Config {
char *** values;
int valuesSize;
};
struct Config read_config(char * cfg);
#endif
This contains information for the config reader to pick up This is read from a file in my program test-config:
{
ID:001
TITLE:Russian Spy Infiltration
DESCRIPTION:Those darn russian spies have done it again.
}
{
ID:002
TITLE:American Enthusiasts
DESCRIPTION:America!!!!!
}
The error that prints
{
ID:001
TITLE:Russian Spy Infiltration
DESCRIPTION:Those darn russian spies have done it again.
}
{
ID:002
malloc(): corrupted top size
fish: Job 1, './bm' terminated by signal SIGABRT (Abort)
EDIT: Instead of using sizeof(), I replaced them with strlen()
newCfg.values[newCfg.valuesSize][valuesPtr][0] = (char*)malloc(sizeof(split)*sizeof(char));
Why sizeof(split)? That's the same as sizeof(char*), which is obviously wrong. Did you mean to use strlen?
Also, given `
struct Config {
char *** values;
int valuesSize;
};
and
char * config;
this line has two problems:
newCfg.values = (char****)malloc(sizeof(char****)*sizeof(config));`
First, sizeof(config) is the size of the pointer, not what it points to (and it points to a char of size one...). You probably wanted strlen(). Maybe.
And you are using sizeof(char****) even though values is a char ***. That won't cause a problem with the size on most systems, but it's still wrong. And if you follow the pattern, it will cause serious problems with smaller numbers if *s.
And many would say there's a third problem - you don't cast the return value from malloc() in C.

How to check if a file exists in a given path in C?

I am trying to find the file(say marks.txt) in the particular path passed as argument to a function. Is it possible to give the filename and path as arguments to a function which checks if the file exists and prints out the path?
The below function only takes path as argument.
int fileexists(const char *path){
File *ptr = fopen(path, "r");
if (fptr == NULL)
return 0;
fclose(fptr);
return 1;
}
The required function prototype :
int fileexists(const char *path, const char *filename)
There are two parts to this question, and the right answers to them depend on what you're trying to do.
Concatenate a directory name and a file name to form a full path name.
Determine whether a file (referred to by a full path name) exists or not.
Concatenating a directory name and a file name is straightforward. Your friendsstrcpy and strcat will do most of the work. There are a few minor details to be careful of: (a) You'll need a big enough buffer for the full pathname, and you'll need to decide whether to use a fixed-size array (perhaps of size MAX_PATH), or a malloc'ed buffer; (b) you might need to insert an explicit '/' character (and it usually doesn't hurt to stick one in even if the directory string already ends in one); (c) under Windows you might want to use '\\' instead of '/'.
And then determining whether a file named by a full pathname exists is already well answered over at What's the best way to check if a file exists in C?. The big question to ask here is, are you asking whether the file exists in preparation to doing something with the file? If so, you have a serious vulnerability if you check for the file's existence, but then before you do the other thing, something else happens to cause the file to appear or disappear. So rather than checking-and-then-doing, it's usually better to just try doing the other thing, and deal gracefully with any errors.
The function you have checks if the file can be opened, but it will fail for some files that exist but you have no rights to open. I'd use stat instead. To concatenate the path and filename you can use string functions.
The usual Unix C APIs are dismal. It takes lots of effort to do the simplest of things correctly - and even then I'm not sure that I didn't forget some Unix-ism like signal handling or some obscure error cases. I.e. stuff that's rather trivial to get right in modern C++.
I wish someone designed a modern C system API and implemented it for at least Linux, so that our suffering would end...
Usually, string concatenation requires some higher level API to be done while maintaining a modicum of sanity. Thus, the example below uses a strbuilder class to build the string. This makes things vaguely readable and avoids most common mistakes.
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct strbuilder {
unsigned items, item;
size_t length, *lengths;
char *str, *dst;
};
bool strbuilder_pass(struct strbuilder *builder, int *rc);
void strcat_str(struct strbuilder *builder, const char *src);
void strcat_c_ifnone(struct strbuilder *builder, char c);
bool strbuilder_is_freed(const struct strbuilder *builder);
int fileExists(const char *path, const char *filename)
{
const char pathSep = '/';
int rc;
struct strbuilder bld = {0};
while (strbuilder_pass(&bld, &rc))
{
strcat_str(&bld, path);
strcat_c_ifnone(&bld, pathSep);
strcat_str(&bld, filename);
if (!rc)
{
struct stat statbuf;
printf("path = %s\n", bld.str);
rc = stat(bld.str, &statbuf);
}
}
assert(strbuilder_is_freed(&bld));
return rc;
}
int main()
{
int rc = fileExists("/", "dev");
assert(rc == 0);
return 0;
}
The string building is controlled by a strbuilder_pass function, which advances the string builder's state through five passes of operation:
Determine the number of items whose width has to be stored (avoids the need to call strlen twice).
Prepare the length storage vector. Determine the length of the buffer needed.
Prepare the output string buffer. Concatenate the elements into the buffer.
Use the output string buffer.
Free the output string buffer.
This API is not particularly special, but fits this use case. Some other ad-hoc approach would work too, but this is IMHO a bit more elegant.
void strbuilder_free(struct strbuilder *builder)
{
free(builder->lengths);
free(builder->str);
memset(builder, 0, sizeof(*builder));
}
bool strbuilder_pass(struct strbuilder *builder, int *rc)
{
if (!builder->length) {// start of pass 1
builder->length = 1; /*term*/
*rc = EAGAIN;
return true;
}
else if (!builder->lengths) // end of pass 1
{
builder->lengths = malloc(sizeof(*builder->lengths) * builder->items);
if (builder->lengths)
return true;
*rc = ENOMEM;
}
else if (!builder->str) // end of pass 2
{
builder->dst = (builder->str = malloc(builder->length));
builder->item = 0;
builder->length = 0;
if (builder->dst) {
*builder->dst = '\0';
return true;
}
*rc = ENOMEM;
}
else if (builder->dst) // end of pass 3
{
while (*builder->dst) { // include optional content
builder->dst++; // skip
builder->length++;
}
builder->dst = NULL;
*rc = 0;
return true;
}
else if (!builder->dst) // end of pass 4 (if any)
{}
else {
*rc = EINVAL;
}
strbuilder_free(builder);
return false;
}
void strcat_str(struct strbuilder *builder, const char *src)
{
if (!src)
return;
if (!builder->lengths) // pass 1
builder->items ++;
else if (!builder->str) // pass 2
{
size_t len = strlen(src);
builder->lengths[builder->item++] = len;
builder->length += len;
}
else if (builder->dst) // pass 3
{
size_t len = builder->lengths[builder->item++];
if (*builder->dst && (!len || *builder->dst != *src))
{
builder->dst++;
builder->length++;
}
memcpy(builder->dst, src, len);
builder->dst += len;
builder->length += len;
*builder->dst = '\0';
}
}
void strcat_c_ifnone(struct strbuilder *builder, char c)
{
if (!builder->lengths) {} // pass 1
else if (!builder->str) // pass 2
{
if (c) builder->length ++;
}
else if (builder->dst) // pass 3
{
if (!builder->length || builder->dst[-1] != c)
*(builder->dst) = c;
}
}
bool strbuilder_is_freed(const struct strbuilder *builder)
{
return !builder || (!builder->lengths && !builder->str);
}
You probably want something like this (no error checking for brevity):
...
#include <string.h> // for str* functions
#include <unistd.h> // for access
#include <stdlib.h> // for malloc
...
int fileexists(const char *path, const char *filename)
{
char *name= malloc(strlen(path) + strlen(filename) + 1);
strcpy(name, path);
strcat(name, filename);
int retval = access(name, F_OK) == 0;
free(name);
return retval;
}
Call like this:
if (fileexists("/some/path/", "somefilename.txt")) ...

Array of jump tables in C

I'm trying to optimize access to some jump tables I have made, they are as follows:
int (*const usart_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[USART_READ_WRITE_CLEAR])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[USART_READ_WRITE_CLEAR])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
As you can see, the functions are for accessing a usart peripheral on a hardware level and are arranged in the table in the order of read/write/clear.
What I am attempting to do is have another jump table of jump tables, this way I can either run through initializing all the usart's registers in startup or simply change a single register later if desired.
i.e.
<datatype> (*usart_peripheral_table[<number of jump tables>])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
This way I can expose that table to my middleware layer, which will help maintain a standard across changing HALs, and also I can use a define to index this table i.e.
fn_ptr = usart_peripheral_table[CTRL_TABLE]
fn_ptr[WRITE](bitmask);
fn_ptr[READ](buffer);
As you may have already guessed, I am struggling to figure out how to construct this table. I figured it is one of two things:
Another simple array of pointers, as even a jump table itself is just an array of pointers. Hence my initialization would be:
const int* (*usart_peripheral_table[<number of jump tables])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
However this doesn't seem to be working. Then I thought:
An array of pointers to pointers. So I tried all kinds of combos:
const int**(*usart_perip...
const int**(usart_perip...
const int** (*usart_peripheral_table[<number of jump tables])() =
{&usart_ctrl_table, &usart_frame_table[0], usart_trig_ctrl_table};
Nothing seems to work. Do I need to store the address of the lower jump tables in yet another pointer before assigning that variable to a pointer-to-pointer array? i.e.
int* fn_ptr = usart_ctrl_table;
<dataytype>(*const usart_periph[<number>])() = {fn_ptr};
Thanks in advance, any help would be greatly appreciated.
MM25
EDIT:
const int** (*const peripheral_table[1])() =
{&usart_ctrl_table[0]};
const int** (*const peripheral_table[1])() =
{usart_ctrl_table};
The above both give the error "initialization from incomaptible pointer type", as do all other combinations I have tried
You might find that defining a typedef for your function pointers makes your code easier to read and maintain (although I’ve seen people recommend against it too):
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
uart_ctl_func uart_ctl_jump_table[][UART_RWC] = {
{ uart_read, uart_write, uart_clear },
{ uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_jump_table[0][1](); // Write.
uart_ctl_jump_table[1][0](); // Read.
uart_ctl_jump_table[1][2](); // Clear.
return EXIT_SUCCESS;
}
The next step might be to make the jump table a struct so you end up writing Uart_ctl_table.frame.read(), or to at least define an enum for the constants.
#include <stdio.h>
#include <stdlib.h>
#define UART_RWC 3U
typedef int (*uart_ctl_func)(void);
int uart_read(void)
{
printf("Read.\n");
fflush(stdout);
return 0;
}
int uart_write(void)
{
printf("Write.\n");
fflush(stdout);
return(0);
}
int uart_clear(void)
{
printf("Clear.\n");
fflush(stdout);
return 0;
}
typedef struct {
uart_ctl_func read;
uart_ctl_func write;
uart_ctl_func clear;
} uart_ctl_set_t;
typedef struct {
uart_ctl_set_t ctrl;
uart_ctl_set_t frame;
uart_ctl_set_t trig;
} uart_ctl_table_t;
const uart_ctl_table_t uart_ctl_table = {
.ctrl = { uart_read, uart_write, uart_clear },
.frame = { uart_read, uart_write, uart_clear },
.trig = { uart_read, uart_write, uart_clear }
};
int main(void)
{
uart_ctl_table.ctrl.write(); // Write.
uart_ctl_table.frame.read(); // Read.
uart_ctl_table.trig.clear(); // Clear.
return EXIT_SUCCESS;
}
Just add a * like you added [] when defining an array.
int zg_usartCtrlRead();
int zg_usartCtrlWrite();
int zg_usartCtrlClr();
int zg_usartFrameRead();
int zg_usartFrameWrite();
int zg_usartFrameClr();
int zg_usartTrigctrlRead();
int zg_usartTrigctrlWrite();
int zg_usartTrigctrlClr();
int (*const usart_ctrl_table[])() =
{zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr};
int (*const usart_frame_table[])() =
{zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr};
int (*const usart_trig_ctrl_table[])() =
{zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr};
int (* const * const usart_peripheral_table[])() =
{usart_ctrl_table, usart_frame_table, usart_trig_ctrl_table};
Usage:
usart_peripheral_table[1][2](5, 1, 3, 5, 6);
Btw, an empty parameter list on function declaration () means unspecified number and type of arguments. Do (void) if you want no arguments passed to your function.
This:
const int* (*usart_peripheral_table[<number of jump tables])();
Is an array of functions pointers that take unspecified number of arguments and return a pointer to constant integer.
This:
const int** (*usart_peripheral_table[<number of jump tables])()
Is an array of function pointers that take unspecified number of arguments and return a pointer to a pointer to a constant integer.
You can also go with a 2D array:
int (* const usart_peripheral_table_2d[][3])() = {
{
zg_usartCtrlRead, zg_usartCtrlWrite, zg_usartCtrlClr,
}, {
zg_usartFrameRead, zg_usartFrameWrite, zg_usartFrameClr,
}, {
zg_usartTrigctrlRead, zg_usartTrigctrlWrite, zg_usartTrigctrlClr,
},
};
But maybe you want to write accessor functions that will return a pointer to an array of functions. Nothing simpler!
#include <stddef.h>
int (*usart_ctrl_table_get(size_t idx))() {
return usart_ctrl_table[idx];
}
int (*usart_frame_table_get(size_t idx))() {
return usart_frame_table[idx];
}
int (*usart_trig_ctrl_table_get(size_t idx))() {
return usart_trig_ctrl_table[idx];
}
int (* const (* const usart_peripheral_table_indirect[])(size_t))() = {
usart_ctrl_table_get,
usart_frame_table_get,
usart_trig_ctrl_table_get,
};
Usage sample:
int main() {
usart_peripheral_table_indirect[2](1)();
}

Segmentation fault with -O3 flag [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Edit: I am really sorry if I have wasted time of your guys, I was running out of time when posting this problem. Here comes the code that I have done my best to minimize it
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum Error {
ERROR_UNRESOLVED_NAME = 1,
ERROR_CANNOT_OPEN_FILE,
ERROR_NO_ARGV,
ERROR_UNRECOGNIZED_SYMBOL,
ERROR_UNCOMPLETED_SENTENCE,
ERROR_RECURSIVE_SELF
};
struct _Piece;
typedef struct _Piece *(*PieceFunc)(struct _Piece *, void *);
struct _Piece {
PieceFunc function;
void *backpack;
};
typedef struct _Piece Piece;
Piece *piece_create(PieceFunc func, void *pack) {
Piece *piece = malloc(sizeof(Piece));
piece->function = func;
piece->backpack = pack;
return piece;
}
typedef struct _Record {
char *name;
int name_len;
Piece *piece;
struct _Record *previous;
} Record;
Record *record_register(Record *pre, char *name, int name_len, Piece *piece) {
Record *record = malloc(sizeof(Record));
record->name = name;
record->name_len = name_len;
record->piece = piece;
record->previous = pre;
return record;
}
typedef struct {
char *file_name;
char *source;
int length;
int current;
int line;
int column;
} Source;
Source *source_create(char *s, int len, char *file_name) {
Source *source = malloc(sizeof(Source));
source->source = s;
source->file_name = file_name;
source->length = len;
source->current = 0;
source->line = source->column = 1;
return source;
}
Piece *apply(Piece *caller, Piece *callee) {
return caller->function(callee, caller->backpack);
}
// Part 3, internals
Piece *internal_self(Piece *callee, void *backpack) {
if (callee->function == internal_self) {
fprintf(stderr,
"recursive `self` calling between two pieces\n"
"piece 1 backpack: %p\n"
"piece 2: %p backpack: %p",
backpack, callee, callee->backpack);
exit(ERROR_RECURSIVE_SELF);
}
return apply(callee, piece_create(internal_self, backpack));
}
Piece *internal_put(Piece *callee, void *backpack) {
int *p_char = callee->backpack;
putchar(*p_char);
return piece_create(internal_self, NULL);
}
Source *main_create_source(char *file_name) {
FILE *source_file = fopen(file_name, "r");
if (!source_file) {
fprintf(stderr, "cannot open file \"%s\"\n", file_name);
exit(ERROR_CANNOT_OPEN_FILE);
}
char *source = NULL;
int length = 0;
while (true) {
char *line = NULL;
int line_len = 0;
line_len = (int)getline(&line, (size_t *)&line_len, source_file);
if (line_len < 0) {
break;
}
if (source == NULL) {
source = line;
} else {
source = realloc(source, sizeof(char) * (length + line_len + 1));
strcat(source, line);
// free(line);
}
length += line_len;
}
fclose(source_file);
return source_create(source, length, file_name);
}
#define MAIN_REGISTER_INTERNAL(record, name, func) \
record = record_register(record, name, sizeof(name) - 1, \
piece_create(func, NULL)); \
printf("%p %p\n", record, record->previous);
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "please specify source file by command line argument\n");
exit(ERROR_NO_ARGV);
}
Record *r = NULL;
MAIN_REGISTER_INTERNAL(r, "put", internal_put);
printf("main %p\n", r);
Source *s = main_create_source(argv[1]);
printf("main %p\n", r);
}
At first, the program crashed with a segmentation fault, I located the bad access code line, which have been deleted in this code demo. I figure out the original bug is that variable r in main would unexpected change after an unrelated calling to main_create_source, which would be demonstrated like this (save this code file as foo.c)
$ cc -O0 -g foo.c
$ ./a.out futaba_test.ftb
0x7fc0024025b0 0x0
main 0x7fc0024025b0
main 0x7fc0024025b0
$ cc -O3 -g foo.c
$ ./a.out futaba_test.ftb
0x7fe861c025b0 0x0
main 0x7fe861c025b0
main 0x7fe800000000
The behavior varied when changing optimization level. It has nothing todo with EOF since I have removed it, and in my opinion the memory for strcat's destination is rich enough. Thanks for any help.
By the way if there is any requirement to point out the purpose of this snippet. This is an interpreter for a minimal language I am working on. It is able to evaluate small source code snippet at the time and this is the first time I have tried to build it with -O3. The bug will only disappear without any level optimization.
(The following is the original post and is able to be ignored.)
I have this code file. When compiling with cc -O0 futaba.c, and running it with ./a.out futaba_test.ftb, the result will be
0x7fba60c025b0 0x0
0x7fba60c025e0 0x7fba60c025b0
0x7fba60c02610 0x7fba60c025e0
0x7fba60c02640 0x7fba60c02610
0x7fba60c02670 0x7fba60c02640
0x7fba60c026b0 0x7fba60c02670
0x7fba60c026d0 0x7fba60c026b0
0x7fba60c02700 0x7fba60c026d0
0x7fba60c02730 0x7fba60c02700
main 0x7fba60c02730
main 0x7fba60c02730
A%
(Zsh add the postfix %) everything is going well. But when compiling with -O3 rather than -O0, than result will be
0x7f8f274025b0 0x0
0x7f8f274025e0 0x7f8f274025b0
0x7f8f27402610 0x7f8f274025e0
0x7f8f27402640 0x7f8f27402610
0x7f8f27402670 0x7f8f27402640
0x7f8f274026b0 0x7f8f27402670
0x7f8f274026d0 0x7f8f274026b0
0x7f8f27402700 0x7f8f274026d0
0x7f8f27402730 0x7f8f27402700
main 0x7f8f27402730
main 0x7f8f00000000
[1] 27811 segmentation fault ./a.out futaba_test.ftb
The last two main line print different address, and the second one is not valid, which cause the stack overflow bug later in record_resolve function.
What is the problem?
That's a lot of code, but here's at least a flag:
char source_fetch(Source *s) {
return s->current == s->length ? EOF : s->source[s->current];
}
This forces EOF into a char, which is a very bad idea. That's why all standard C functions that can return EOF (like getchar() return int.
No idea what an optimizing compiler can make out of that, but once you factor in code that waits for EOF using that ... it's smelly.
Note: this is perhaps bad form as an answer; but it's pointing out a concrete problem with the code.
Also none of the heap allocations seems to have code looking for NULL being returned; that's a bit scary too.

Resources