diff options
| author | Paul Eggert | 2016-08-02 21:04:28 -0400 |
|---|---|---|
| committer | Paul Eggert | 2016-08-02 21:06:02 -0400 |
| commit | d98f7834266beed9b1c7b561168570938ec2c6bf (patch) | |
| tree | e07a19d3702ef4de56c754c7387c3ceeb6a2a790 /src | |
| parent | 07e9281f7a17f47493a5f611f6c6ea40fa286614 (diff) | |
| download | emacs-d98f7834266beed9b1c7b561168570938ec2c6bf.tar.gz emacs-d98f7834266beed9b1c7b561168570938ec2c6bf.zip | |
Fix (mapcar F S) crash when F alters S’s length
* src/fns.c (mapcar1): Return number of elements computed,
which can be less than LENI if the function alters the list.
All callers changed. (Bug#24118)
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 77 |
1 files changed, 30 insertions, 47 deletions
| @@ -2517,11 +2517,13 @@ usage: (nconc &rest LISTS) */) | |||
| 2517 | } | 2517 | } |
| 2518 | 2518 | ||
| 2519 | /* This is the guts of all mapping functions. | 2519 | /* This is the guts of all mapping functions. |
| 2520 | Apply FN to each element of SEQ, one by one, | 2520 | Apply FN to each element of SEQ, one by one, storing the results |
| 2521 | storing the results into elements of VALS, a C vector of Lisp_Objects. | 2521 | into elements of VALS, a C vector of Lisp_Objects. LENI is the |
| 2522 | LENI is the length of VALS, which should also be the length of SEQ. */ | 2522 | length of VALS, which should also be the length of SEQ. Return the |
| 2523 | number of results; although this is normally LENI, it can be less | ||
| 2524 | if SEQ is made shorter as a side effect of FN. */ | ||
| 2523 | 2525 | ||
| 2524 | static void | 2526 | static EMACS_INT |
| 2525 | mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq) | 2527 | mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq) |
| 2526 | { | 2528 | { |
| 2527 | Lisp_Object tail, dummy; | 2529 | Lisp_Object tail, dummy; |
| @@ -2564,14 +2566,18 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object fn, Lisp_Object seq) | |||
| 2564 | else /* Must be a list, since Flength did not get an error */ | 2566 | else /* Must be a list, since Flength did not get an error */ |
| 2565 | { | 2567 | { |
| 2566 | tail = seq; | 2568 | tail = seq; |
| 2567 | for (i = 0; i < leni && CONSP (tail); i++) | 2569 | for (i = 0; i < leni; i++) |
| 2568 | { | 2570 | { |
| 2571 | if (! CONSP (tail)) | ||
| 2572 | return i; | ||
| 2569 | dummy = call1 (fn, XCAR (tail)); | 2573 | dummy = call1 (fn, XCAR (tail)); |
| 2570 | if (vals) | 2574 | if (vals) |
| 2571 | vals[i] = dummy; | 2575 | vals[i] = dummy; |
| 2572 | tail = XCDR (tail); | 2576 | tail = XCDR (tail); |
| 2573 | } | 2577 | } |
| 2574 | } | 2578 | } |
| 2579 | |||
| 2580 | return leni; | ||
| 2575 | } | 2581 | } |
| 2576 | 2582 | ||
| 2577 | DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0, | 2583 | DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0, |
| @@ -2581,34 +2587,26 @@ SEPARATOR results in spaces between the values returned by FUNCTION. | |||
| 2581 | SEQUENCE may be a list, a vector, a bool-vector, or a string. */) | 2587 | SEQUENCE may be a list, a vector, a bool-vector, or a string. */) |
| 2582 | (Lisp_Object function, Lisp_Object sequence, Lisp_Object separator) | 2588 | (Lisp_Object function, Lisp_Object sequence, Lisp_Object separator) |
| 2583 | { | 2589 | { |
| 2584 | Lisp_Object len; | ||
| 2585 | EMACS_INT leni; | ||
| 2586 | EMACS_INT nargs; | ||
| 2587 | ptrdiff_t i; | ||
| 2588 | Lisp_Object *args; | ||
| 2589 | Lisp_Object ret; | ||
| 2590 | USE_SAFE_ALLOCA; | 2590 | USE_SAFE_ALLOCA; |
| 2591 | 2591 | EMACS_INT leni = XFASTINT (Flength (sequence)); | |
| 2592 | len = Flength (sequence); | ||
| 2593 | if (CHAR_TABLE_P (sequence)) | 2592 | if (CHAR_TABLE_P (sequence)) |
| 2594 | wrong_type_argument (Qlistp, sequence); | 2593 | wrong_type_argument (Qlistp, sequence); |
| 2595 | leni = XINT (len); | 2594 | EMACS_INT args_alloc = 2 * leni - 1; |
| 2596 | nargs = leni + leni - 1; | 2595 | if (args_alloc < 0) |
| 2597 | if (nargs < 0) return empty_unibyte_string; | 2596 | return empty_unibyte_string; |
| 2598 | 2597 | Lisp_Object *args; | |
| 2599 | SAFE_ALLOCA_LISP (args, nargs); | 2598 | SAFE_ALLOCA_LISP (args, args_alloc); |
| 2600 | 2599 | ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence); | |
| 2601 | mapcar1 (leni, args, function, sequence); | 2600 | ptrdiff_t nargs = 2 * nmapped - 1; |
| 2602 | 2601 | ||
| 2603 | for (i = leni - 1; i > 0; i--) | 2602 | for (ptrdiff_t i = nmapped - 1; i > 0; i--) |
| 2604 | args[i + i] = args[i]; | 2603 | args[i + i] = args[i]; |
| 2605 | 2604 | ||
| 2606 | for (i = 1; i < nargs; i += 2) | 2605 | for (ptrdiff_t i = 1; i < nargs; i += 2) |
| 2607 | args[i] = separator; | 2606 | args[i] = separator; |
| 2608 | 2607 | ||
| 2609 | ret = Fconcat (nargs, args); | 2608 | Lisp_Object ret = Fconcat (nargs, args); |
| 2610 | SAFE_FREE (); | 2609 | SAFE_FREE (); |
| 2611 | |||
| 2612 | return ret; | 2610 | return ret; |
| 2613 | } | 2611 | } |
| 2614 | 2612 | ||
| @@ -2618,24 +2616,15 @@ The result is a list just as long as SEQUENCE. | |||
| 2618 | SEQUENCE may be a list, a vector, a bool-vector, or a string. */) | 2616 | SEQUENCE may be a list, a vector, a bool-vector, or a string. */) |
| 2619 | (Lisp_Object function, Lisp_Object sequence) | 2617 | (Lisp_Object function, Lisp_Object sequence) |
| 2620 | { | 2618 | { |
| 2621 | register Lisp_Object len; | ||
| 2622 | register EMACS_INT leni; | ||
| 2623 | register Lisp_Object *args; | ||
| 2624 | Lisp_Object ret; | ||
| 2625 | USE_SAFE_ALLOCA; | 2619 | USE_SAFE_ALLOCA; |
| 2626 | 2620 | EMACS_INT leni = XFASTINT (Flength (sequence)); | |
| 2627 | len = Flength (sequence); | ||
| 2628 | if (CHAR_TABLE_P (sequence)) | 2621 | if (CHAR_TABLE_P (sequence)) |
| 2629 | wrong_type_argument (Qlistp, sequence); | 2622 | wrong_type_argument (Qlistp, sequence); |
| 2630 | leni = XFASTINT (len); | 2623 | Lisp_Object *args; |
| 2631 | |||
| 2632 | SAFE_ALLOCA_LISP (args, leni); | 2624 | SAFE_ALLOCA_LISP (args, leni); |
| 2633 | 2625 | ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence); | |
| 2634 | mapcar1 (leni, args, function, sequence); | 2626 | Lisp_Object ret = Flist (nmapped, args); |
| 2635 | |||
| 2636 | ret = Flist (leni, args); | ||
| 2637 | SAFE_FREE (); | 2627 | SAFE_FREE (); |
| 2638 | |||
| 2639 | return ret; | 2628 | return ret; |
| 2640 | } | 2629 | } |
| 2641 | 2630 | ||
| @@ -2661,21 +2650,15 @@ the results by altering them (using `nconc'). | |||
| 2661 | SEQUENCE may be a list, a vector, a bool-vector, or a string. */) | 2650 | SEQUENCE may be a list, a vector, a bool-vector, or a string. */) |
| 2662 | (Lisp_Object function, Lisp_Object sequence) | 2651 | (Lisp_Object function, Lisp_Object sequence) |
| 2663 | { | 2652 | { |
| 2664 | register EMACS_INT leni; | ||
| 2665 | register Lisp_Object *args; | ||
| 2666 | Lisp_Object ret; | ||
| 2667 | USE_SAFE_ALLOCA; | 2653 | USE_SAFE_ALLOCA; |
| 2668 | 2654 | EMACS_INT leni = XFASTINT (Flength (sequence)); | |
| 2669 | if (CHAR_TABLE_P (sequence)) | 2655 | if (CHAR_TABLE_P (sequence)) |
| 2670 | wrong_type_argument (Qlistp, sequence); | 2656 | wrong_type_argument (Qlistp, sequence); |
| 2671 | 2657 | Lisp_Object *args; | |
| 2672 | leni = XFASTINT (Flength (sequence)); | ||
| 2673 | SAFE_ALLOCA_LISP (args, leni); | 2658 | SAFE_ALLOCA_LISP (args, leni); |
| 2674 | mapcar1 (leni, args, function, sequence); | 2659 | ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence); |
| 2675 | ret = Fnconc (leni, args); | 2660 | Lisp_Object ret = Fnconc (nmapped, args); |
| 2676 | |||
| 2677 | SAFE_FREE (); | 2661 | SAFE_FREE (); |
| 2678 | |||
| 2679 | return ret; | 2662 | return ret; |
| 2680 | } | 2663 | } |
| 2681 | 2664 | ||