1

我正在使用 OP-TEE (TrustZone Secure OS) 库用 C 语言开发一个基本应用程序。我在 QEMU 中运行代码。这是发生奇怪行为的代码:

void prepare_rsa_operation(TEE_OperationHandle *handle, uint32_t alg, TEE_OperationMode mode, TEE_ObjectHandle key) {
    TEE_Result ret = TEE_SUCCESS;   
    TEE_ObjectInfo key_info;

    ret = TEE_GetObjectInfo1(key, &key_info);
    if (ret != TEE_SUCCESS) {
        EMSG("TEE_GetObjectInfo1: %#" PRIx32, ret);
        goto err;
    }

    ret = TEE_AllocateOperation(handle, alg, mode, key_info.keySize);
    if (ret != TEE_SUCCESS) {
        EMSG("Failed to alloc operation handle : 0x%x", ret);
        goto err;
    }
    DMSG("========== Operation allocated successfully. ==========");

    ret = TEE_SetOperationKey(*handle, key);
    if (ret != TEE_SUCCESS) {
        EMSG("Failed to set key : 0x%x", ret);
        goto err;
    }
    DMSG("========== Operation key already set. ==========");

err:
    TEE_FreeOperation(handle);
    return 1;
}

发生的问题:
正在打印两个成功的消息(用于操作分配和键设置),但err即使达到标签:TEE_FreeOperation(handle);应该写入TEE_FreeOperation(*handle);。我修复了这个并删除了return, 因为我的函数返回void. 现在,代码运行良好,但据我了解,只有在条件测试( 's)之一失败err时才应该达到标签,因为命令就在其中。ifgoto

我对这种理解有误吗?谁能解释我为什么err即使之前没有发生错误也达到了标签?

4

4 回答 4

3

如果您使用它或在执行之后err:达到标签。这意味着无论功能是否成功,您都会得到清理。这就是开始使用“on error goto”模式的全部原因。gotoDMSG("========== Operation key already set. ==========");

goto 的一个更易读的替代方法是在错误时返回并将清理工作留在外部包装函数中。

于 2018-08-16T14:52:08.243 回答
2

没有特殊的逻辑可以阻止代码越过标签。

按照惯例,goto通常在 C 中用于这种类型的错误处理,但不一定非要如此。的标签goto可以自由放置在函数中的任何位置。例如,您可以这样做:

void f()
{
    int i;
start:
    printf("i=%d\n", i);
    i++;
    if (i < 10) {
        goto start;
}

但请不要。

于 2018-08-16T14:58:52.580 回答
1

如果通过正常的执行流程到达,则不会跳过带标签的语句。IOW,给定代码

if ( condition )
{
  goto err;
}

err:
  // error handling code

// regular code

如果condition计算结果为 false,则后面的代码err仍然会被执行,因为它跟在if语句后面。您可以通过使用第二个标签和来避免它goto

if ( condition )
{
  goto err;
}
goto normal;

err:
  // error handling code

normal:
  // regular code

但是找出一种解决问题的无goto方法会更好。

于 2018-08-16T15:18:33.040 回答
1

很像 switch-case 语句中的 Case 标签,当通过正常的代码流到达时,标签将落入下一条指令。简直就是一个可以跳到的地方。在发生错误后进行清理时会利用此功能。例如,如果您正在分配一堆东西并且发生错误,您可以根据遇到错误的时间跳转到清理代码的不同部分:

int func(void) {
    int ret = -1;
    int *x = malloc(sizeof(*x));
    if (/* some error condition */) {
        goto CLEANUP1;
    }
    int *y = malloc(sizeof(*y));
    if (/* some error condition */) {
        goto CLEANUP2;
    }
    int *z = malloc(sizeof(*z));
    if (/* some error condition */) {
        goto CLEANUP3;
    }
    ret = 0;
    /* do whatever successful operations you want here */

    CLEANUP3:
    free(z);
    CLEANUP2:
    free(y);
    CLEANUP1:
    free(x);
    return ret;
}

因此,对于上面的代码片段,在正常无错误执行的情况下,所有malloc'd 变量都会free在离开函数之前得到 d 。malloc如果ing后有错误x,则跳转到CLEANUP1标签和free xmalloc如果ing之后有错误z,那么你也malloc'd xand y,所以你跳转到CLEANUP3标签,free z然后会掉到其他两个frees。

于 2018-08-16T15:55:32.283 回答