Merge pull request #2771 from colinleroy/much-smaller-strndup
Make strndup smaller, safer, faster
This commit is contained in:
@@ -4,53 +4,50 @@
|
|||||||
; char* __fastcall__ strndup (const char* S, size_t maxlen);
|
; char* __fastcall__ strndup (const char* S, size_t maxlen);
|
||||||
;
|
;
|
||||||
|
|
||||||
.importzp ptr4, c_sp
|
.importzp tmp1, tmp2, ptr2
|
||||||
.import _strdup, _strlen, pushax, popax, _realloc
|
.import _strncpy, _strlen, _malloc
|
||||||
|
.import pushax, popax, incsp2, incax1, swapstk
|
||||||
|
.import ___errno
|
||||||
|
|
||||||
.export _strndup
|
.export _strndup
|
||||||
|
|
||||||
_strndup:
|
.include "errno.inc"
|
||||||
sta maxlen ; Remember maxlen
|
|
||||||
stx maxlen+1
|
|
||||||
|
|
||||||
jsr popax ; Duplicate string
|
.proc _strndup
|
||||||
jsr _strdup
|
sta tmp1 ; Remember maxlen
|
||||||
jsr pushax ; Remember result
|
stx tmp1+1
|
||||||
|
|
||||||
jsr _strlen ; Check length,
|
jsr popax ; Get string
|
||||||
cpx maxlen+1
|
jsr pushax ; Keep it in TOS
|
||||||
bcc out ; Return directly if < maxlen
|
|
||||||
|
jsr _strlen ; Get string length,
|
||||||
|
cpx tmp1+1 ; Compare to max,
|
||||||
|
bcc alloc
|
||||||
bne :+
|
bne :+
|
||||||
cmp maxlen
|
cmp tmp1
|
||||||
bcc out
|
bcc alloc
|
||||||
|
|
||||||
: ldy #$00 ; Otherwise, point to end of string,
|
: lda tmp1 ; Use maxlen if shorter
|
||||||
lda maxlen
|
ldx tmp1+1
|
||||||
clc
|
|
||||||
adc (c_sp),y
|
|
||||||
sta ptr4
|
|
||||||
lda maxlen+1
|
|
||||||
iny
|
|
||||||
adc (c_sp),y
|
|
||||||
sta ptr4+1
|
|
||||||
|
|
||||||
dey ; Cut it short,
|
alloc: jsr incax1 ; Add 1 for terminator
|
||||||
tya
|
jsr _malloc ; Allocate output
|
||||||
sta (ptr4),y
|
cpx #$00 ; Check allocation
|
||||||
|
beq errmem
|
||||||
|
|
||||||
ldx maxlen+1 ; And finally, realloc to maxlen+1
|
jsr swapstk ; Put dest in TOS and get string back
|
||||||
ldy maxlen
|
jsr pushax ; Put src in TOS
|
||||||
iny
|
lda tmp1 ; Get length for strncpy
|
||||||
tya
|
ldx tmp1+1
|
||||||
bne :+
|
|
||||||
inx
|
|
||||||
: jsr _realloc ; TOS still contains result
|
|
||||||
; We consider realloc will not fail,
|
|
||||||
; as the block shrinks.
|
|
||||||
jsr pushax ; push/pop for size optimisation
|
|
||||||
out:
|
|
||||||
jmp popax
|
|
||||||
|
|
||||||
.bss
|
jsr _strncpy ; Copy
|
||||||
|
pha ; Terminate
|
||||||
|
lda #$00
|
||||||
|
sta (ptr2),y
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
maxlen: .res 2
|
errmem: ldy #ENOMEM
|
||||||
|
sty ___errno
|
||||||
|
jmp incsp2 ; Pop string and return
|
||||||
|
.endproc
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "unittest.h"
|
#include "unittest.h"
|
||||||
|
|
||||||
#define SHORT_STR "abcdefghijklmnopqrstuvwxyz"
|
#define SHORT_STR "abcdefghijklmnopqrstuvwxyz"
|
||||||
@@ -56,5 +57,17 @@ TEST
|
|||||||
free(dst);
|
free(dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
src = malloc(LONG_STR_LEN+1);
|
||||||
|
ASSERT_IsTrue(src != NULL, "Could not allocate source string");
|
||||||
|
memset(src, 'a', LONG_STR_LEN);
|
||||||
|
src[LONG_STR_LEN] = '\0';
|
||||||
|
|
||||||
|
dst = strndup(src, 30);
|
||||||
|
ASSERT_IsTrue(dst != NULL, "strndup returned NULL");
|
||||||
|
free(dst);
|
||||||
|
|
||||||
|
dst = strndup(src, LONG_STR_LEN);
|
||||||
|
ASSERT_IsTrue(errno == ENOMEM, "error is not ENOMEM");
|
||||||
|
ASSERT_IsTrue(dst == NULL, "strndup did not return NULL");
|
||||||
}
|
}
|
||||||
ENDTEST
|
ENDTEST
|
||||||
|
|||||||
Reference in New Issue
Block a user