2013-10-11 5 views
0

저는 lex를 사용하여 스캐너를 구현하고 있습니다. 나는 파싱하는 동안 심볼 테이블을 만들고 싶다. 두 개의 구조체, SymbolEntry 및 SymbolTable (아래) 있습니다. 대부분의 경우, 심볼을 삽입하는 함수 (registerID, 아래 참조)를 호출 할 때 항목에 대한 모든 정보가 있습니다. 그러나 상수가있을 때도 값을 얻고 싶지만 처음 엔 항목을 만들 때 바로 사용할 수 없습니다. 나중에 코드에서 항목 값을 변경하려고하면 해당 항목에서 사용하는 전체 메모리 블록이 무효화되고 이름과 값이 가비지를 인쇄합니다. 여기 구조체 문자열 변경

두 구조체이다 :

typedef struct{ 
    char* type; 
    char* name; 
    char* value; 
} SymbolEntry; 
typedef struct{ 
    SymbolEntry *entries; 
    size_t size; 
    size_t capacity; 
} SymbolTable; 

이것이 {id}가 일치 할 때 호출 registerID 함수이다. yytext에는 ID가 들어 있습니다.

int registerID(char* type){ 
    //create a new symbol entry with the specified type and name and a default value 
    SymbolEntry e; 
    e.type = type; 
    e.name = (char *)calloc(yyleng+1, sizeof(char)); 
    strcpy(e.name, yytext); 
    e.value = ""; 
    prevSym = insertSymbol(&table, e); 
    return prevSym; 
} 

이것은 insertSymbol(SymbolTable* st, SymbolEntry entry)에 대한 관련 코드입니다. pos은 항상 삽입 할 때 배열의 마지막 요소입니다 (그렇지 않으면 항목이 고유하지 않고 pos이 반환됩니다). 렉스 프레임 워크는 즉시 상수 이름을 다음과 같은 값을 일치 한 후

st->entries[pos].name = (char *)calloc(strlen(entry.name)+1, sizeof(char)); 
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char)); 
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char)); 
strcpy(st->entries[pos].name, entry.name); 
strcpy(st->entries[pos].type, entry.type); 
strcpy(st->entries[pos].value, entry.value); 

나중에이 코드는

table.entries[prevSym].value = (char *)calloc(yyleng+1, sizeof(char)); 
strcpy(table.entries[prevSym].value, yytext); 

왜이에하여 SymbolEntry을 무효화 않습니다 (직접 <CONSTANT_VAL>{number}에 대한 규칙에서) 수행 배열의이 위치와 어떻게 안전하게 value의 내용을 바꿀 수 있습니까?

편집 : 이것은 정수에서만 발생하는 것이 아닙니다. 처음 두 SymbolEntry은 항상 쓰레기입니다. 나는 아마 그들 모두가 그렇다는 것을 의미한다고 가정하고 있지만 다른 것들은 단지 덮어 쓰지 않았다.

또한 이후에 registerID을 호출하면 데이터가 손상 될 수 있습니다. 단 9 개의 기호로 처음 두 개는 쓰레기이고 34 개는 처음입니다. 변수없이 구문 분석 할 텍스트를 더 추가해도 아무런 문제가 없습니다.

SOLVED 글쎄, 우연히 길을 따라 어딘가에 선을 실수로 삭제했다는 것이 밝혀졌습니다. 실수로 전화가 initSymbolTable으로 지워졌습니다. chux가 테이블을 초기화하는 방법을 묻는 것에 감사드립니다. 미안합니다.

+0

을 고려 당신은 어떻게 ST-> 항목 [POS]를 할당하는거야? 한 가지 가능성은 할당 된 메모리를 초과하여 쓰는 것입니다. – KayakDave

+0

크기는 16으로 시작하지만'size == capacity' 인 경우에는 크기를 두 배로 재 할당합니다. 이 점검은 모든 삽입 작업 후에 수행됩니다. – Jaws212

+0

또한 SymbolEntry 배열을 1024에 할당하려고했지만 여전히 유효하지 않습니다. – Jaws212

답변

1

2 잠재적 인 문제.

1 - 동적

// Fields set with non-malloc'ed memory 
e.type = type; 
e.value = ""; 
// Fields set with malloc'ed memory 
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char)); 
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char)); 
strcpy(st->entries[pos].type, entry.type); 
strcpy(st->entries[pos].value, entry.value); 

이 모두 유효 메모리와 두 번째 경우의 필드를 설정 비교 메모리를 입력합니다. 관심사는 연속적인 사용이다. OP는 어떻게 free() 또는 realloc() 두 번째 종류가 아니라 첫 번째 알지. 추가 우려 사항 : registerID(char* type)을 사용하면 type에 전달 된 값이 나중에 해당 포인터가 type 필드를 통해 사용될 때 유효한 방법임을 알 수 있습니까? 제안 :

e.type = strdup(type); // or the usual strlen()+1, malloc() and copy 
e.value = strdup(""); 

2 - yyleng의 유형과 설정은 표시되지 않습니다. 어쩌면 strlen(e.name) 등과 비교했을 때 충분히 크지 않을 수도 있습니다.

[편집] 검토 후, 나는 진짜 e.type = type;이 문제라고 생각합니다. e.type은 자체 복사본 type이 필요합니다.

마이너 :

// st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char)); 
// strcpy(st->entries[pos].type, entry.type); 
size_t Length = strlen(entry.type) + 1; 
st->entries[pos].type = malloc(Length); 
memcpy(st->entries[pos].type, entry.type, Length); 
+0

모든 할당을'strdup()'호출로 변경했습니다. 'yyleng'은 lex에 의해 정의되고'yytext'의 길이입니다. 각 레코드의 각 필드는'type == CONSTANT'에 대한 'value'를 제외하고 한 번만 생성됩니다. 그런 다음 두 개의 특정 장소 중 하나에서만 변경됩니다. 이 시점에서 (입력 파일의 상수 없이도) 상위 3/32 SymbolEntries가 손상되었습니다. 'strdup()'가 사용될 때마다 어떻게 될지 모르겠습니다. 최악의 경우, 대신 메모리 오버플로를 처리해야합니다. – Jaws212

+0

흠. 디버그 목적으로'e.name = strdup (yytext)'와'table.entries [prevSym] .value = strdup (yytext) '를 고려해보십시오. 이렇게해도 문제가 해결되지 않으면 게시되지 않은 코드에 문제가 있어야합니다. – chux

+0

@ Jaws212'st '에 대한 메모리는 어떻게 할당됩니까? – chux