C
Backstory
Vợ tôi thừa hưởng một con mèo từ gia đình. † Thật không may, tôi rất dị ứng với động vật. Con mèo đã vượt quá giới hạn của nó và đáng lẽ đã bị tiêu hủy ngay cả trước khi chúng tôi nhận được nó, nhưng cô ấy không thể tự mình thoát khỏi nó vì giá trị tình cảm của nó. Tôi ấp ủ một kế hoạch nhằm chấm dứt của tôi đau khổ của nó.
Chúng tôi đang đi nghỉ dài ngày, nhưng cô ấy không muốn lên mèo ở văn phòng bác sĩ thú y. Cô lo lắng về việc mắc bệnh hoặc bị ngược đãi. Tôi đã tạo ra một máy nạp mèo tự động để chúng tôi có thể để nó ở nhà. Tôi đã viết phần sụn của vi điều khiển trong C. Tệp chứa có main
vẻ giống với mã bên dưới.
Tuy nhiên, vợ tôi cũng là một lập trình viên và biết cảm xúc của tôi đối với con mèo, vì vậy cô ấy khăng khăng đòi xem xét lại mã trước khi đồng ý để nó ở nhà mà không cần giám sát. Cô có một số mối quan tâm, bao gồm:
main
không có chữ ký tuân thủ tiêu chuẩn (đối với triển khai được lưu trữ)
main
không trả về giá trị
tempTm
được sử dụng chưa được khởi tạo kể từ khi malloc
được gọi thay vìcalloc
malloc
không nên bỏ giá trị trả về
- thời gian của vi điều khiển có thể không chính xác hoặc cuộn qua (tương tự như các vấn đề về thời gian 2038 của Y2K hoặc Unix)
- các
elapsedTime
biến thể không có đủ tầm
Phải mất rất nhiều sức thuyết phục, nhưng cuối cùng cô ấy đã đồng ý rằng các vấn đề không phải là vấn đề vì nhiều lý do (điều đó không làm tổn thương rằng chúng tôi đã trễ chuyến bay). Vì không có thời gian để thử nghiệm trực tiếp, cô ấy đã phê duyệt mã và chúng tôi đã đi nghỉ. Khi chúng tôi trở về một vài tuần sau đó, tôi đau khổ của con mèo đã kết thúc (mặc dù kết quả là bây giờ tôi đã có rất nhiều nhiều hơn nữa).
Kịch bản hoàn toàn hư cấu, không phải lo lắng.
Mã
#include <time.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
//#include "feedcat.h"
// contains extern void FeedCat(struct tm *);
// implemented in feedcat.c
// stub included here for demonstration only
#include <stdio.h>
// passed by pointer to avoid putting large structure on stack (which is very limited)
void FeedCat(struct tm *amPm)
{
if(amPm->tm_hour >= 12)
printf("Feeding cat dinner portion\n");
else
printf("Feeding cat breakfast portion\n");
}
// fallback value calculated based on MCU clock rate and average CPI
const uintmax_t FALLBACK_COUNTER_LIMIT = UINTMAX_MAX;
int main (void (*irqVector)(void))
{
// small stack variables
// seconds since last feed
int elapsedTime = 0;
// fallback fail-safe counter
uintmax_t loopIterationsSinceFeed = 0;
// last time cat was fed
time_t lastFeedingTime;
// current time
time_t nowTime;
// large struct on the heap
// stores converted calendar time to help determine how much food to
// dispense (morning vs. evening)
struct tm * tempTm = (struct tm *)malloc(sizeof(struct tm));
// assume the cat hasn't been fed for a long time (in case, for instance,
// the feeder lost power), so make sure it's fed the first time through
lastFeedingTime = (size_t)(-1);
while(1)
{
// increment fallback counter to protect in case of time loss
// or other anomaly
loopIterationsSinceFeed++;
// get current time, write into to nowTime
time(&nowTime);
// calculate time since last feeding
elapsedTime = (int)difftime(nowTime, lastFeedingTime);
// get calendar time, write into tempTm since localtime uses an
// internal static variable
memcpy(&tempTm, localtime(&nowTime), sizeof(struct tm));
// feed the cat if 12 hours have elapsed or if our fallback
// counter reaches the limit
if( elapsedTime >= 12*60*60 ||
loopIterationsSinceFeed >= FALLBACK_COUNTER_LIMIT)
{
// dispense food
FeedCat(tempTm);
// update last feeding time
time(&lastFeedingTime);
// reset fallback counter
loopIterationsSinceFeed = 0;
}
}
}
Hành vi không xác định:
Đối với những người không muốn tự mình tìm kiếm UB:
Chắc chắn có hành vi cụ thể cục bộ, không xác định và xác định thực hiện trong mã này, nhưng tất cả đều hoạt động chính xác. Vấn đề nằm ở các dòng mã sau:
struct tm * tempTm //...
//...
memcpy(&tempTm, localtime(&nowTime), sizeof(struct tm));
memcpy
ghi đè tempTM
con trỏ thay vì đối tượng mà nó trỏ tới, đập vỡ ngăn xếp. Điều này ghi đè, ngoài những thứ khác, elapsedTime
và loopIterationsSinceFeed
. Đây là một ví dụ chạy trong đó tôi đã in ra các giá trị:
pre-smash : elapsedTime=1394210441 loopIterationsSinceFeed=1
post-smash : elapsedTime=65 loopIterationsSinceFeed=0
Xác suất giết mèo:
- Với môi trường thực thi bị ràng buộc và chuỗi xây dựng, hành vi không xác định luôn xảy ra.
- Tương tự, hành vi không xác định luôn ngăn không cho mèo nạp hoạt động như dự định (hay đúng hơn, cho phép nó "hoạt động" như dự định).
- Nếu máng ăn không hoạt động, rất có khả năng con mèo sẽ chết. Đây không phải là một con mèo có thể tự chống đỡ, và tôi đã thất bại khi yêu cầu người hàng xóm nhìn vào nó.
Tôi ước tính rằng con mèo chết với xác suất 0,995 .