-2

From what i heard or read, segmentation fault occurs when we try to write on read only memory or writing on unallocated memory. I searched the whole code putting a lot of printf to see where it happens and why but i got no better results.

See the full source HERE

Below is sample code which i suspect has something to do with segfault.


static bool init_rand(void *data, size_t size)
{
    FILE *stream = fopen("/dev/urandom", "r");
    if (stream == NULL)
        return false;
    bool ok = (fread(data, sizeof(uint8_t), size, stream) == size);
    for (int i = 0; i < size; i++) {
           printf("%02x", ((unsigned char *) data) [i]);
    }
    fclose(stream);
    return ok;
}

union uint256_s
{
    uint8_t i8[32];
    uint16_t i16[16];
    uint32_t i32[8];
    uint64_t i64[4];
};
typedef union uint256_s uint256_t;


static inline uint256_t sha256(const void *data, size_t len)
{
    secp256k1_sha256_t cxt;
    secp256k1_sha256_initialize(&cxt);
    secp256k1_sha256_write(&cxt, (uint8_t *)data, (int)len);
    uint256_t res;
    secp256k1_sha256_finalize(&cxt, (uint8_t *)&res);
    return res;
}

static uint256_t sha256d(const void *data, size_t len)
{
    uint256_t hsh = sha256(data, len);
    hsh = sha256(&hsh, sizeof(hsh));
    return hsh;
}

struct starp
{
    uint256_t starp;
    uint128_t counter;
};


static struct starp *make_starp(void)
{
    struct starp *starp = (struct starp *)malloc(sizeof(struct starp));
    assert(starp != NULL);
    starp->counter = 0;
    if (!init_rand(starp, sizeof(struct starp)))
    {
        fprintf(stderr, "error: failed to init random starp\n");
        exit(EXIT_FAILURE);
    }
    if (starp->counter == 0)     // Sanity check...
    {
        fprintf(stderr, "error: random starp initialization failed\n");
        exit(EXIT_FAILURE);
    }
    return starp;
}

static uint256_t rand256(struct starp *starp)
{
    starp->counter++;
    return sha256(starp,sizeof(struct starp));
}


static uint160_t gen_hash160(const uint8_t *pub_key)
{
    uint160_t hsh160 = hash160(pub_key);
    return hsh160;
}



#define BASE_MAX            0xFFFF

static secp256k1_gej_t bases[BASE_MAX];
static secp256k1_scalar_t priv_bases[BASE_MAX];

#define OFFSET_MAX_COL      9
#define OFFSET_MAX_ROW      BASE_MAX

#define BITS                16
#define NUM_PARTS(n)        (((n) - 1) / 16 + 1)

#define NUM_INIT_WORKERS    4

static secp256k1_ge_t offsets[OFFSET_MAX_ROW][OFFSET_MAX_COL];
static secp256k1_scalar_t priv_offsets[OFFSET_MAX_ROW][OFFSET_MAX_COL];


static bool read_pub_table(FILE *stream);
static bool write_pub_table(FILE *stream);
static bool read_priv_table(FILE *stream);
static bool write_priv_table(FILE *stream);


static void *init_worker(void *arg)
{
    struct starp *starp = make_starp();
    size_t i = (size_t)arg;

    for (size_t j = 0; j < OFFSET_MAX_ROW; j++)
    {
        int overflow = 0;
        do
        {
            uint256_t x = rand256(starp);
            secp256k1_scalar_set_b32(&priv_offsets[j][i], x.i8, &overflow);
        }
        while (overflow);
        secp256k1_gej_t tmp;
        secp256k1_ecmult_gen(&cxt->ecmult_gen_ctx, &tmp, &priv_offsets[j][i]);
        secp256k1_ge_set_gej(&offsets[j][i], &tmp);
    }
    free(starp);
    putchar('.');
    printf("  Init Worker executes\n");
    fflush(stdout);

    return NULL;
}

When i replace all occurrences of sizeof(struct starp) with other number like 12 segmentation fault occurs but if i put 48 it works.

HERE is my output and i need the program to read 12 bytes instead of 32 bytes priv key.

  • 3
    please provide a [mre], even the link to your "full source" isn't an mre. Things like `struct starp *starp = (struct starp *)malloc(48);` are extremely suspicious. You want to `malloc` the size of your struct using `sizeof`. Even if you know it's 48 now, that may not be true with different compilers, different versions of your compiler, or even different optimization flags of your compiler. Furthermore, you can run your code under valgrind and/or use the `-fsanitize=address` flag if using gcc to help find the problems. – yano Jan 18 '23 at 03:51
  • 1
    Don't "mitigate" segmentation faults, their cause must be found and fixed. Your post does not contaion adequate information. However, you seem to have indicated that `struct starp *starp = (struct starp *)malloc(48);` is wrong and at least part of your problem and this does look off. The normal correct way to write this to get the size correct even if the definition of starp changes is `struct starp *starp = malloc( sizeof( *starp ) );` (unless you were allocating an array or struct starp contained a flexible array member). I also find `size_t i = (size_t)arg;` suspicious. – Avi Berger Jan 18 '23 at 03:52
  • The easiest way to track down a repeatable segmentation fault in a large piece of code is to run it under a debugger. That'll usually tell you the exact line where the segmentation fault happened, and then it's usually straightforward to debug. So, please, do that if you can! (Is there any reason you can't?) – Steve Summit Jan 18 '23 at 12:28
  • Note that naming a struct type starp, a member of struct starp with the name starp, and a variable of type pointer to struct starp also with the name starp is a good way to confuse yourself and others reading your code. This may account for what I believe to be your incorrect calls to init_rand() in make_starp() and sha256() in rand256(). These should possibly be something similar to: `init_rand( &(starp->starp), sizeof(starp->starp) );` and `sha256( &(starp->starp), sizeof(starp->starp) )` – Avi Berger Jan 18 '23 at 19:02
  • Your title question is about a segmentation fault and that is what people are responding to. I now note that at the end of your post that you say you experience the fault when you deliberately don't allocate enough memory for an object. That is a reasonable, but not a required result. It is a good thing when it happens as it lets you know you messed up and your code has a serious problem. The message is "Don't deliberately break your code." If you allocate memory for an object, you MUST allocate enough memory to hold the object. – Avi Berger Jan 18 '23 at 19:12
  • At the end of OP " need . . . to read 12 bytes instead of 32" That is a different issue, but I now suspect is your intended question. This would be done by knowing where you want to put those 12 bytes and then reading those 12 bytes and putting them in that location. It is not done by trying to place an object in a space that is too small to hold it. I'm guessing that you want to put them somewhere in starp->starp. That's a different ?, but you can do that. Guessing 'init_rand( &(starp->starp.i8[ start_pos ]), desired_size );'. But you probably need to 0 fill the rest of starp->starp. – Avi Berger Jan 18 '23 at 19:35
  • @AviBerger yes, `malloc(sizeof(struct starp)` allocates space for 48 bytes to be read from urandom but only 32 bytes are used as priv key, if i manually allocates space for 12 bytes , segfault happens just after reading and storing them – terry franklin Jan 19 '23 at 01:48
  • malloc(sizeof(struct starp) allocates the correct amount of space for a struct starp. If you want to allocate a struct starp object that is how much you _must_ allocate, That is how big it is. If you allocate less memory, then your code is broken. Reading and storing bytes is a different matter and does not change this. Wherever you choose to store bytes you read needs enough room to accommodate them. You can store them in a run-time sized buffer. You could even maintain a pointer to such a buffer in a struct object, though you aren't currently doing that. – Avi Berger Jan 19 '23 at 02:29

1 Answers1

1

Segmentation fault just means "you are writing to memory which you don't have access too". The causes for it could be many, including array out of bounds, invalid pointer de-referencing, non-initialized pointers, stack overflows, race condition bugs etc etc. The meaning is essentially just "you have a bug in your program".


In your case the hard-coded malloc(48) with the magic number 48 getting pulled out of a hat is very suspicious. You should never have such "magic numbers" in your code, that appear out of the blue with no explanation why. This line should almost certainly be rewritten as:

struct starp *starp = malloc(sizeof(*starp));

Another case of "code smell" which is not necessarily a bug is: size_t i = (size_t)arg;. The function definition static void *init_worker(void *arg) implies that this is a callback for a thread(?), such as a pthread.

There's a common bad practice to pass an integer to a pthread by casting it to void* and back into an integer. That's not safe nor portable however, since pointers and integers are not necessarily of the same size. And also the OS/MMU is free to raise an exception if your integer value does not correspond to an aligned address. This instruction trap can happen during conversion and not necessarily just when the pointer is de-referenced.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • (Regarding that pthread hack, it is funny that the very same people who insists that POSIX is _the_ standard for portable code are also the ones most prone to write the most horrible, non-portable code the world has ever seen...) – Lundin Jan 18 '23 at 09:06
  • i have edited and added more code for better understanding – terry franklin Jan 18 '23 at 10:20
  • 1
    @terryfranklin _Way_ too much code, I'm not going to read that. Examples here are supposed to be minimal and only contain relevant parts, not your whole code base. – Lundin Jan 18 '23 at 10:23