You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决C语言段错误?替换sizeof值触发问题求助

段错误排查与修复需求

我知道Segmentation fault(段错误)通常因写入只读内存或未分配内存导致,添加大量printf调试后仍未找到原因。以下是怀疑引发段错的代码片段:

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;
}

当把所有sizeof(struct starp)替换为12时触发段错误,替换为48则正常。我需要程序读取12字节而非32字节私钥,求解决该段错问题。


问题根因与修复方案

核心问题

struct starp的实际内存大小是48字节(uint256_t占32字节,uint128_t占16字节),强行将操作长度替换为12会导致:

  • init_rand仅初始化结构体前12字节,starp->counter的剩余字节为未定义垃圾值,后续的counter == 0检查逻辑完全失效。
  • rand256中sha256只读取12字节,但结构体实际占用48字节,读取范围不完整会引发内存越界或逻辑错误,最终触发段错。
  • 需求是“读取12字节私钥”,但错误修改了整个结构体的操作长度,完全偏离目标。

修复步骤

1. 调整结构体定义,明确12字节随机种子

把原结构体中的32字节uint256_t改为12字节数组,直接对应需求:

struct starp
{
    uint8_t starp_seed[12];  // 12字节随机种子
    uint128_t counter;
};

2. 修改相关函数的操作范围

  • make_starp中修正初始化范围:只初始化12字节的种子部分,去掉无意义的counter检查(因为counter初始化为0后会自增,不需要随机初始化):
static struct starp *make_starp(void)
{
    struct starp *starp = (struct starp *)malloc(sizeof(struct starp));
    assert(starp != NULL);
    starp->counter = 0;
    // 仅初始化12字节的种子
    if (!init_rand(starp->starp_seed, sizeof(starp->starp_seed)))
    {
        fprintf(stderr, "error: failed to init random starp\n");
        exit(EXIT_FAILURE);
    }
    return starp;
}
  • rand256中读取完整结构体:确保sha256读取整个结构体的有效内存,避免越界:
static uint256_t rand256(struct starp *starp)
{
    starp->counter++;
    // 读取完整结构体大小,保证内存访问合法
    return sha256(starp, sizeof(struct starp));
}

3. 适配secp256k1私钥要求

secp256k1_scalar_set_b32要求输入是32字节的合法标量(不超过曲线阶)。如果用12字节生成私钥,需要将12字节扩展为32字节(比如补0或做哈希),否则overflow会持续触发,导致死循环:

// 示例:将12字节种子哈希为32字节后再作为标量
uint256_t seed_hash = sha256(starp->starp_seed, sizeof(starp->starp_seed));
secp256k1_scalar_set_b32(&priv_offsets[j][i], seed_hash.i8, &overflow);

调试建议

  • 用gdb定位段错:运行gdb ./你的程序,崩溃后输入bt查看调用栈,直接找到崩溃代码行。
  • 开启编译警告:添加-Wall -Wextra编译选项,提前发现内存越界、类型不匹配等潜在问题。

内容的提问来源于stack exchange,提问作者terry franklin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:40:52