2016-12-01 50 views
4

我很想知道如果在字符串周围保留一个元数据的头部会是安全的,而不是实现相关的?在malloc'd字符串之前保存元数据是否安全?

我不知道,如果下面将跨平台工作或有东西,可能会导致读取错误sizetotal字段或是否会有这样做对缓冲区realloc有问题吗?

#include <stdlib.h> 
#include <stdio.h> 

typedef struct{ 
    int size; 
    int total; 
    char buf[]; 
} String; 

int get_str_size(char *str){ 
    String *pointer = (void*)(str-sizeof (String)); 
    return pointer->size; 
} 

int get_str_total(char *str){ 
    String *pointer = (void*)(str-sizeof (String)); 
    return pointer->total; 
} 

char *init_string(int sz){ 
    size_t header_size = 1 + sz + sizeof(String); 
    String *pointer = calloc(header_size, 1); 

    pointer->total = 0; 
    pointer->size = sz; 

    return pointer->buf; 
} 

char *realloc_string(char *str, int sz){ 
    int old = get_str_size(str); 
    int new = old + sz; 

    String *pointer1 = (void*)(str-sizeof (String)); 
    size_t header_size = 1 + new + sizeof(String); 
    String *pointer2 = realloc(pointer1, header_size); 

    return pointer2->buf; 
} 

int main(void){ 
    char *str = NULL; 
    str = init_string(10); 

    printf("Length of str:%d\n", get_str_size(str)); 
    printf("Total malloc'd:%d\n", get_str_total(str)); 
    free(str - sizeof (String)); 

    return 0; 
} 
+1

我看不到任何问题。但是我会添加'free_string'函数。 – freestyle

+1

我认为除了缺少错误检查之外,它是相当安全的。我想如果分配失败,我会让'init_string'和'realloc_string'返回'NULL'。其他我要做的事情包括将'init_string'重命名为'alloc_string',当'str'为'NULL'时使'realloc_string'与'init_string'相同,并添加'free_string'函数接受一个有效的字符串或NULL指针。 –

+0

请注意,MS Windows中的'BSTR'字符串做了类似的事情;它们在返回的指针前有一个32位长的前缀。 –

回答

1

这是不安全的。

它没有未定义的行为(UB)也没有实现定义的行为,因为合法的,除了小的int/size_t问题。

不幸的是代码隐藏太多。 @Jonathan Leffler。考虑下面编译的代码,然后调用UB。

printf("%d\n", get_str_size("Hello Word")); 

组函数将使用类型String作为参数,而不是char *更好。这就是类型检查的目的。


小问题。

C 字符串是数组。数组索引最好使用size_t类型。 int可能太窄。

String *String_copy(const char *src) { 
    size_t len = strlen(src); 
    //       v-v Overflow potential 
    String *dest = init_string(len); 
    ... 
    return dest; 
} 

可能int溢出。重新预防。

//      v----v int math 
// size_t header_size = 1 + sz + sizeof(String); 
size_t header_size = sz + sizeof(String) + 1; 
// or 
size_t header_size = sizeof(String) + sz + 1; 

代码缺乏其他功能,应补充集。 @Ian

缺少错误检查,但假设这是为了简化代码表示。

相关问题